CHAPTER 24
MISCELLANEOUS TOPICS.
UNICODE STRINGS:
I shall deal with the matter of Unicode character strings here, as we must encounter them somewhere, since Windows sometimes makes use of them, instead of ordinary byte sized character strings, as in menu template strings, for example.
Windows programmers had to face the problem of the existence of multiple languages with different kinds of alphabet characters. The normal ASCII keyboard characters require only one byte to specify the character code. One byte, however, can specify a maximum of 255 different characters. A word sized character code system, however, can specify up to 0xffff, or 65535 different characters, and this is the basis of the word sized Unicode character system. Such a system is large enough to represent characters in all possible alphabets, including codes for Chinese characters, for example. The ASCII characters are thus also included in the Unicode system, by expanding them to word sized characters, and a programmer will need to know how this is done.
The conversion of ASCII characters to Unicode simply requires prefixing the hex version of the
character code by 00. For example, the hex version of the character code for the capital letter J is the byte sized value 0x4a, so the corresponding Unicode character would be the word sized value 0x004a.
Windows normally specifies that strings must be terminated in a zero. In the case of Unicode, the terminating zero must be the word sized version 0x0000.
In the declarations of Windows API functions as 'extern', which is required in order that your code can call them as procedures external to your code, some will include equates like
_GetMessage@16 equ _GetMessageA@16
The 'A' in GetMessageA refers to the ANSI version of GetMessage, which means that there is also a GetMessageW@16 alternative, which is a Unicode version of GetMessage. These alternatives apply only to all those API functions where character strings are involved. The names of API function which do not involve character strings have only one form, without an 'A' or 'W'.
MULTI-COMPONENT APPLICATIONS:
If you have an application with a number of separate component windows you have two choices as to how to create and operate the different component windows. You can either create one window class, and create several different windows of the same class, or you can create a separate class for each window.
In the first alternative you have only one callback function, and must distinguish between the different windows, which all share the same code, by means of the different window handles. In the second alternative, each window can have its own callback function, since registering a window class involves specifying a callback function address. Each window can therefore have virtually an entirely separate code of its own, and share only the WinMain and message loop part of the code.
It is really a matter for the programmer as to which of these alternatives might seem to be the most convenient.
An important consideration with multi-component applications, involving a number of windows, which are not child windows of one another, is where you want a change in the position of one window to be reflected by a reactionary change in the positions of
other windows, as, for example, if you want to avoid one window overlapping another.
The problem is that if, for example, you call the MoveWindow API function to move one of the other windows, messages will be sent to that window, and these will obliterate the message parameters of the current window before the current window response is complete, if both windows share the same message queue.
A way to deal with this, that appears to work, is to save all current message parameters, before calling the MoveWindow or other functions for the other window, and then restore them before exiting the current window current callback response.
If you have different window classes, you can send a message to the other window, after completing the current window response. It is best to send such a message from the current window WM_PAINT message response, which is the last message to be processed from the queue.
In general, however, it is necessary to experiment with such innovations, in any particular case, in order determine with certainty what will work properly and what will not.
PAINTING THE NON-CLIENT AREA TO CREATE YOUR OWN WINDOWS:
The introductory chapter on the Windows operating system listed a series of windows messages that a program code receives when it is started and its window is first put on the screen. Among these messages are those of the form WM_NC… All such messages refer to the non-client area of the screen, that is the window border and title bar and menu bar, if there is one.
These messages are implemented by the operating system by being sent to the DefWindowProc API function, to which all messages not dealt with by the program code are sent for default processing. If you intercept any WM_NC… type message and do not send it to the DefWindowProc function, it will not be implemented by the system.
If you want to paint the non-client area yourself, and create a window with a non-client area that looks different to the standard window, the following considerations regarding non-client messages will be relevant.
If you want to avoid the non-client area being painted, you must abort both the WM_NCACTIVATE and WM_NCPAINT messages. In this case the non-client area will be created, but will be invisible. However, when the mouse button moves in the non-client area, three non-standard boxes (exit, maximise, and minimise) may appear at
the top right corner of the non-client area, even thought the rest of the non-client area remains invisible and these boxes may work in some unpredictable ways To avoid this, you must create the window with a flag like WS_OVERLAPPED, to create a window which does not include the system menu boxes.
In such a case, however, you cannot use the exit box to close the window, even if you click the mouse in the top right corner area where it should be. If you are painting the non-client area yourself, you will have to paint an exit box, and other boxes, yourself, and use the x and y positions of the mouse cursor, in WPARAM_LOWORD and WPARAM_HIWORD respectively, returned with the WM_NCHITTEST message, to find whether or not the mouse cursor is within the area of the exit box. The x and y positions are measured relative to the top left corner of the entire screen. In addition, there is a problem if you want to minimise such a window to the taskbar, and you will probably have to create a special, second, minimised window to take care of this.
In general, you should not interfere with the non-client area until you are experienced and have gained confidence with ordinary Windows programming, so that you can possibly deal with the unpredictable results that can follow from interfering with the non-client area of a window.
CREATING YOUR OWN SPLASH SCREENS, ETC.:
It is possible to put a window on the screen having no non-client features at all, such as title bars, borders, or context menu items, and this is another way to create your own windows, and possibly create a pseudo-non-client area yourself, which, in this case, need not be confined to the dimensions of the standard non-client area.
You may also recall seeing various commercial programs which initially open a temporary, introductory window on the screen, which has no normal non-client area features, and which disappears automatically before the main program window appears. These windows are called 'splash screens', and are windows created without a non-client area.
Such windows consist of nothing other than a client rectangle alone, which will thus initially appear on the screen as completely invisible. To create such a window, you use the CreateWindow api function with nothing but the WS_POPUP style specified. This doesn't mean that the window will be a popup
window that will disappear if you click a mouse button outside its client area. It means only that the window has a popup style, which means that it is nothing other than a client rectangle. It will, however, transmit windows client messages in the same way as any regular window, and you can also paint the client area in the normal way. With such a window, of course, you will have to write the code yourself to provide the user with the ability to move or drag the window, and also close it, since these responses cannot be provided by the operating system in the absence of a non-client area.
If you write code to enable you to drag the window in response to WM_MOUSEMOVE messages, you will find that, if you move the mouse too quickly, the mouse cursor will escape from the window and the window will not be able to follow it once it is outside the window boundary. To avoid this (at least as much as possible) you have to capture the mouse cursor with the window by using the SetCapture and ReleaseCapture API functions.
HOW TO CREATE A WINDOW WITH A CORRECT CLIENT RECT SIZE:
When creating a window by using the CreateWindowEx API function, the specified size of the window refers to the overall size, including the non-client area. Sometimes, however, you may want to create a window with a client rectangle of a specific size, rather than specifying the size of the entire window.
There are two ways in which this can be done. The first involves using the AdjustWindowRect API function, before calling the CreateWindowEx function. You specify the desired client rectangle size to AdjustWindowRect, and it calculates and returns the overall size of the window, to be passed to the CreateWindowEx function. I have found, however, that there can be problems with using this method,
especially if you want to load a menu after creating the window. Personally, I prefer to use the alternative method, described below.
In this alternative, you can create a window having the size of the client rectangle, but don't show it on the screen. Then, just before displaying it on the screen, call the GetClientRect API function and calculate the difference between the actual client rect size, returned by this function, and the desired client rect size. Add or subtract the differences, as required, to the overall size of the window, and then call the MoveWindow API function, giving it the modified window size, and then call ShowWindow, to display it on the screen. You will then have a window with the desired client rect dimensions.
Part I: Part I Introduction
Chapter 1: Binary numbers, code, and procedures
Chapter 3: Assembly Language
Chapter 4: Assembly Language Code example
Chapter 5: Macros and HLA
Chapter 6: HLA code example
Chapter 7: The Windows operating system
Chapter 8: Data Structures
Chapter 9: How to Create a Windows Program
Chapter 10: How to Create an Exe File
Chapter 11: Structured Programming and OOP
Part II: Part II Introduction
Chapter 12: Debugging a Windows Program Code
Chapter 13: Painting the Window Client Area
Chapter 14: Creating Window Menus
Chapter 15: How to Create Toolbars
Chapter 16: How to Create Popup Menus
Chapter 17: About the Windows Clipboard
Chapter 18: How to Create Bitmaps
Chapter 19: Icons and the Ico Format
Chapter 20: Common Dialog Boxes
Chapter 21: Working with Files
Chapter 22: Scrollbars and Scrolling
Chapter 23: How to Send Data to the Printer
Chapter 24: Miscellaneous Topics
© Alen, June 2014
alen@alenspage.net
Material on this page may be reproduced
for personal use only.