APPUTIL - Application Utility Library SUMMARY ======= The APPUTIL library provides utility classes and functions that are useful for making simple C++ Win32 Windows applications. APPUTIL is provided as part of the Win32 OLE Tutorial code samples. For functional descriptions and a tutorial code tour of APPUTIL, see the Code Tour section below. For details on setting up your system to build and test the code samples in this OLE Tutorial series, see TUTORIAL.TXT. The supplied MAKEFILE is Microsoft NMAKE-compatible. To create a debug build, issue the NMAKE command in the Command Prompt window. Usage ----- APPUTIL.LIB is meant to be statically linked to modules (.EXEs or .DLLs) that use it. You include APPUTIL.H in the module that uses features of APPUTIL.LIB. You must also include APPUTIL.LIB in the LINK command of your application's makefile. For an example of the use of APPUTIL.LIB, see the EXESKEL code sample. Classes ------- The classes provided are: CVirWindow, CVirDialog, CAboutBox, CMsgBox, CMsgLog, CSendLog, and CThreaded. Functions --------- The functions provided are: WindowProc, DialogProc, UcToAnsi, CreateColorScalePalette, PaintWindow, FileExist, MakeFamilyPath, CmdExec, ReadMe, ReadMeFile, ReadSource, and OutputDebugFmt. There are also a series of A_ ANSII versions of OLE service helper functions. The A_ functions are used in conjunction with a matching series of macros in APPUTIL.H to permit compilation of the code samples under both ANSII (default) and UNICODE. These macros and matching A_ functions are for OLE service calls that only accept Unicode string parameters. For example, the standard OLE StgIsStorageFile function only accepts a Unicode string. When compiling a sample for ANSII (ie, UNICODE is not defined), a macro substitutes any StgIsStorageFile calls into A_StgIsStorageFile calls. A_StgIsStorageFile is implemented here in APPUTIL. A_StgIsStorageFile takes the input ANSII string that is passed and converts it into a Unicode string prior to making a call to the actual OLE StgIsStorageFile function. CODE TOUR ========= File Description APPUTIL.TXT This file. MAKEFILE The generic Win32 makefile for this APPUTIL library. APPUTIL.H The include file for the APPUTIL library. Contains the class declarations and function prototypes. APPUTIL.CPP The main implementation file for APPUTIL. An abstract base class, CVirWindow, is declared in APPUTIL.H as an aid in treating a window as a C++ object. Using the CVirWindow class, a window procedure can directly access class members by dereferencing a pointer to an object instance of this class. Through GWL_USERDATA in GetWindowLong and SetWindowLong, the WindowProc member function has access to the "this" pointer. The global WindowProc function is still used, but this scheme allows the global function to forward most message handling to the WindowProc member function of a specific object instance of CVirWindow. The global WindowProc receives the "this" pointer as the lpCreateParams member passed as part of the WM_NCCREATE message. It save the "this" pointer in the GWL_USERDATA field of the window structure. An abstract base class, CVirDialog, which is similar to CVirWindow, is also declared as an aid in treating a dialog box as a C++ object. Using the CVirDialog class, a dialog box procedure can directly access class members by dereferencing a pointer to an object instance of this class. Through GWL_USERDATA in GetWindowLong and SetWindowLong, the DialogProc member function has access to the "this" pointer. The global DialogProc function is still used, but this scheme allows the global function to defer most message handling to the DialogProc member function of a specific object instance of CVirDialog. The functionality is very similar to CVirWindow described above. The CAboutBox class is declared to allow creation of a common About dialog box in applications. The class is derived from the CVirDialog abstract class and illustrates its use. The CMsgBox class is declared to provide simple message boxes to display error and notice messages. The message strings in the message box can be specified as string literals, string variables, or resource string identifiers. The Error and Note methods take string literals or string variables. The ErrorID and NoteID methods take resource string identifiers. In addition, the Notice message box methods have variants that support message string formatting in the style of the C standard library function printf. These member functions support a variable argument list, NoteFmt, and NoteFmtID. The CMsgLog class is declared to provide a facility for logging debug trace messages to a Listbox control. This class is for code samples that use debug messages to announce internal activity in the code being studied. This message log listbox can be directed to occupy the entire client area of the parent window. An argument to the Create method determines whether the log occupies a detached child window or the entire client area as an integral child window. Message output member functions can use either string resource identifier arguments to retrieve the message strings from the application's resources, or string variables to retrieve the message strings directly. The CMsgLog::MsgFmt method is provided to allow message formatting in the style of the C standard library function wsprintf. This member function supports a variable argument list. The CMsgLog::Copy method is provided to copy the entire contents of the message log to the Windows Clipboard. The CMsgLog logging facility is for examining the tutorial code samples. It works in parallel with the standard OutputDebugString capability. If you are compiling with NODEBUG=1, the debug output is not compiled. In this case, logging support is still available, because it is an integral part of the code sample itself. When compiling for debugging, both outputs are provided for flexibility. Most C++ debuggers have an output window that will display the debug output strings, but the logging facility works whether or not you are running the application under a debugger. The CSendLog trace logging facility is also provided. It operates much like the CMsgLog facility, except that it is intended for an application that logs its activity in an application running in another process. This facility is useful in an out-of-process local server that logs its internal behavior to a display in a client .EXE. CSendLog uses the Win32 SendMessage function with the WM_COPYDATA message to send a block of text data from one process to another. CSendLog duplicates some of the capability of CMsgLog by allowing a local server to have its own log display. The destination of the logging can therefore be switched between the client's logging display and the local server's logging display by calling the LogToServer method. The CThreaded class is provided as a utility base class for providing functionality in derived classes that offer mutually exclusive access among multiple threads to data in objects of the derived class. Derive your class from CThreaded to inherit these features. A typical example of a method in the derived class that exploits these features follows. void CServer::Unlock(void) { if (OwnThis()) { m_cLocks -= 1; if (m_cLocks < 0) m_cLocks = 0; if (0L == m_cObjects && 0L == m_cLocks && IsWindow(m_hWndServer)) PostMessage(m_hWndServer, WM_CLOSE, 0, 0L); UnOwnThis(); } return; } This Unlock method implements numerous thread-safe accesses and changes to the guarded m_cLocks member variable. CServer was derived public from CThreaded. Two CThreaded methods are of value here: OwnThis and UnOwnThis are virtual functions in CThreaded that have default defintions that enforce mutually exclusive access to data in objects of the derived class (like CServer here). You use bracketed pairs of these OwnThis and UnOwnThis methods, as above, to code the protection. OwnThis blocks the currently executing thread until any currently "owning" threads execute the UnOwnThis method. OwnThis returns true if ownership is granted. See the CThreaded method definitions in APPUTIL.CPP for more details. Some general utility functions and macros provided by APPUTIL are briefly described below. OLE often deals with parameters that are pointers to pointers (void**). To capture this as a type, a PPVOID typedef is provided. The DELETE_POINTER macro deletes the object pointed to by a pointer and sets the pointer to NULL. The RELEASE_INTERFACE macro releases a pointer to an interface and sets the pointer to NULL. lRandom is a simple DWORD pseudo-random number generator. Two utility functions are provided for creating color scale palettes and for painting windows with such colors: CreateColorScalePalette and PaintWindow. Lifted from the GDIDEMO sample in the Win32 samples of the Win32 SDK. They are used in these tutorial samples to add color background to the standard Aboutbox dialog. The FileExist utility function indicates whether a specified file exists. The MakeFamilyPath utility function uses GetModuleFileName to dynamically determine the path to the module currently executing and construct a "family" variant of that path with the proper file name extension for a particular purpose. Various such extensions (for example, .HLP, .TXT, and .LIC) are defined in APPUTIL.H for use with this MakeFamilyPath function. The ReadMe utility function is provided to start a reader on the .TXT file that accompanies the current executable. The Windows Notepad (NOTEPAD.EXE) is the default reader. You can specify a different reader by modifying EDITOR_FILE_STR in APPUTIL.H. Like ReadMe, the ReadMeFile utility function is provided to start a reader on a specified .TXT file. The ReadSource utility function is provided to display the Open common dialog box so the user can select any of the source files for the current code sample and start a reader on that file. The Windows Notepad (NOTEPAD.EXE) is the default reader. You can specify a different reader by modifying EDITOR_FILE_STR in APPUTIL.H Then OutputDebugFmt utility function is provided to support formatted (printf-style) variable argument output to the debugger. This function wraps the standard OutputDebugString function. A set of debug output macros is provided to obtain source file and line number information for the debug output. These macros use the function OutputDebugFmt to support variable argument lists in the format of the debug output display string. The debug output macros are: Macro Description ODS Output debug string literal. Example: ODS("String Literal"). ODFn Output formatted debug string using printf-style format string and a variable argument list to correspond to the format. Examples: ODF1("Integer=%i", iInteger); ODF2("Integer=%i String=%s \r\n", iInteger, szString); A set of debug trace logging macros is provided to obtain source file and line number information for the debug output while also logging these messages to a built-in CMsgLog message logging facility in the application. These macros also output the same messages to the debugger using the standard OutputDebugString call. These are convenience macros to perform both the message logging that the application requires and to output the same messages to the debugger, if the application was compiled for debugging and you are running it under a debugger aware of such output. Like the ODFn macros, these macros form a series. For the string literal arguments, do not use the TEXT macro--it is provided inside the macro. Macro Description LOG Log a string literal message. Example: LOG("String Literal"); LOGFn Log a formatted message using printf-style format string and a variable argument list to correspond to the format. Examples: LOGF1("Integer=%i", iInteger); LOGF2("Integer=%i String=%s \r\n", iInteger, szString); LOGID Log a message string retrieved from the module's resources. Example: LOGID(ID_OF_MY_STRING_IN_THE_RESOURCES); LOGERROR Check an error code and if it is an error then fetch the matching error string message from the system tables and log the error. Example: LOGERROR("SysApiThatWasCalled:", ErrorCodeReturned);