/*+========================================================================== File: APPUTIL.CPP Summary: Implementation file for the general application utility classes and functions offered by the APPUTIL library. For a comprehensive tutorial code tour of APPUTIL's contents and offerings see the accompanying APPUTIL.TXT file. For more specific details see the comments dispersed throughout the APPUTIL source code. Classes: CVirWindow, CVirDialog, CAboutBox, CMsgBox, CMsgLog Functions: WindowProc, DialogProc, FileExist, MakeFamilyPath, CmdExec, ReadMe, ReadMeFile, ReadSource, OutputDebugFmt, lRandom, UcToAnsi, A_StringFromGUID2, A_WriteFmtUserTypeStg, A_StgIsStorageFile, A_StgCreateDocfile, A_StgOpenStorage, CreateColorScalePalette, PaintWindow. Origin: 7-27-95: atrent - Created based on WINHLPRS by stevebl. ---------------------------------------------------------------------------- This file is part of the Microsoft OLE Tutorial Code Samples. Copyright (C) Microsoft Corporation, 1996. All rights reserved. This source code is intended only as a supplement to Microsoft Development Tools and/or on-line documentation. See these other materials for detailed information regarding Microsoft code samples. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. ==========================================================================+*/ /*--------------------------------------------------------------------------- We include WINDOWS.H for all Win32 applications. We include TCHAR.H for general Unicode/Ansi prototype of utility functions like _tsplitpath, etc. We include APPUTIL.H for the defines of this APPUTIL library. We use the _NOANSIMACROS_ to turn off the ANSI macro undefines so that function calls to certain OLE APIs inside this module get to the original OLE functions instead of the ANSI surrogates. ---------------------------------------------------------------------------*/ #include #include #define _NOANSIMACROS_ #include "apputil.h" #if !defined(UNICODE) /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: UcToAnsi Summary: Convert a UNICODE input string to an output ANSI string. Args: LPWSTR pszUc Pointer to a caller's input UNICODE wide string. LPSTR pszAnsi Pointer to a caller's output ANSI string. int cch Character count. If 0 then use length of pszUc. Returns: HRESULT Standard OLE result code. NOERROR for success. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ HRESULT UcToAnsi( LPWSTR pszUc, LPSTR pszAnsi, int cch) { HRESULT hr = E_FAIL; int cSize; int cOut; if (0 == cch) cSize = WideCharToMultiByte(CP_ACP,0,pszUc,-1,NULL,0,NULL,NULL); else cSize = cch; if (0 != cSize) { cOut = WideCharToMultiByte(CP_ACP,0,pszUc,-1,pszAnsi,cSize,NULL,NULL); if (0 != cOut) hr = NOERROR; } return hr; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: A_StringFromGUID2 Summary: ANSI Surrogate for the OLE Unicode API call. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ STDAPI A_StringFromGUID2(REFGUID guid, LPSTR pszGUID, int cch) { HRESULT hr = E_INVALIDARG; LPWSTR pszUc; IMalloc* pIMalloc; if (NULL != pszGUID && 0 < cch) { hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc); if (SUCCEEDED(hr)) { pszUc = (LPWSTR)pIMalloc->Alloc((cch+1)*sizeof(TCHAR)); pIMalloc->Release(); if (NULL != pszUc) { hr = StringFromGUID2(guid, pszUc, cch); if (SUCCEEDED(hr)) hr = UcToAnsi(pszUc, pszGUID, cch); CoTaskMemFree((void *)pszUc); } else hr = E_OUTOFMEMORY; } } return hr; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: A_WriteFmtUserTypeStg Summary: ANSI Surrogate for the OLE Unicode API call. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ STDAPI A_WriteFmtUserTypeStg( IStorage* pIStorage, CLIPFORMAT ClipFmt, LPSTR pszUserType) { HRESULT hr = E_INVALIDARG; WCHAR szUc[MAX_PATH]; if (NULL != pszUserType) { MultiByteToWideChar(CP_ACP, 0, pszUserType, -1, szUc, MAX_PATH); hr = WriteFmtUserTypeStg(pIStorage, ClipFmt, szUc); } return hr; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: A_StgIsStorageFile Summary: ANSI Surrogate for the OLE Unicode API call. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ STDAPI A_StgIsStorageFile( LPSTR pszFileName) { HRESULT hr = E_INVALIDARG; WCHAR szUc[MAX_PATH]; if (NULL != pszFileName) { MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szUc, MAX_PATH); hr = StgIsStorageFile(szUc); } return hr; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: A_StgCreateDocfile Summary: ANSI Surrogate for the OLE Unicode API call. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ STDAPI A_StgCreateDocfile( LPSTR pszFileName, DWORD dwAccessMode, DWORD reserved, IStorage** ppIStorage) { HRESULT hr = E_INVALIDARG; WCHAR szUc[MAX_PATH]; LPWSTR pszUc = NULL; // Null the caller's output variable. *ppIStorage = NULL; if (NULL != pszFileName) { MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szUc, MAX_PATH); pszUc = szUc; } hr = StgCreateDocfile(pszUc, dwAccessMode, reserved, ppIStorage); return hr; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: A_StgOpenStorage Summary: ANSI Surrogate for the OLE Unicode API call. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ STDAPI A_StgOpenStorage( LPSTR pszFileName, IStorage* pIStorage, DWORD dwAccessMode, SNB snbExclude, DWORD reserved, IStorage** ppIStorage) { HRESULT hr = E_INVALIDARG; WCHAR szUc[MAX_PATH]; LPWSTR pszUc = NULL; // Null the caller's output variable. *ppIStorage = NULL; if (NULL != pszFileName) { MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szUc, MAX_PATH); pszUc = szUc; } hr = StgOpenStorage( pszUc, pIStorage, dwAccessMode, snbExclude, reserved, ppIStorage); return hr; } #endif // !UNICODE /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: lRandom Summary: Simple random number generator. Returns a random DWORD. Args: void Returns: DWORD Random number. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ DWORD lRandom(void) { static DWORD glSeed = (DWORD)-365387184; glSeed *= 69069; return(++glSeed); } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: CreateColorScalePalette Summary: This routine creates a palette representing the scale values of a particular RGB color. A gray-scale palette can also be created. Borrowed from GDIDEMO in the Win32 samples of the Win32 SDK. Args: HDC hDC, Handle to device context. int nColor New color. Returns: HPALETTE Handle to new pallete. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ HPALETTE CreateColorScalePalette(HDC hDC, int nColor) { HPALETTE hPalette; GLOBALHANDLE hMem; LPLOGPALETTE lpMem; int idx,nReserved,nSize; hPalette = NULL; if(GetDeviceCaps(hDC,RASTERCAPS) & RC_PALETTE) { nReserved = GetDeviceCaps(hDC,NUMRESERVED); nSize = GetDeviceCaps(hDC,SIZEPALETTE) - nReserved; hMem = GlobalAlloc( GHND, (DWORD)sizeof(LOGPALETTE)+(sizeof(PALETTEENTRY)*nSize)); if(hMem) { if(lpMem = (LPLOGPALETTE)GlobalLock(hMem)) { lpMem->palNumEntries = (WORD)nSize; lpMem->palVersion = (WORD)0x0300; switch(nColor) { case COLOR_SCALE_RED: for(idx=0; idx < nSize; idx++) { lpMem->palPalEntry[idx].peRed = (BYTE)idx; lpMem->palPalEntry[idx].peGreen = 0; lpMem->palPalEntry[idx].peBlue = 0; lpMem->palPalEntry[idx].peFlags = PC_RESERVED; } break; case COLOR_SCALE_GREEN: for(idx=0; idx < nSize; idx++) { lpMem->palPalEntry[idx].peRed = 0; lpMem->palPalEntry[idx].peGreen = (BYTE)idx; lpMem->palPalEntry[idx].peBlue = 0; lpMem->palPalEntry[idx].peFlags = PC_RESERVED; } break; case COLOR_SCALE_BLUE: for(idx=0; idx < nSize; idx++) { lpMem->palPalEntry[idx].peRed = 0; lpMem->palPalEntry[idx].peGreen = 0; lpMem->palPalEntry[idx].peBlue = (BYTE)idx; lpMem->palPalEntry[idx].peFlags = PC_RESERVED; } break; default: case COLOR_SCALE_GRAY: for(idx=0; idx < nSize; idx++) { lpMem->palPalEntry[idx].peRed = (BYTE)idx; lpMem->palPalEntry[idx].peGreen = (BYTE)idx; lpMem->palPalEntry[idx].peBlue = (BYTE)idx; lpMem->palPalEntry[idx].peFlags = PC_RESERVED; } break; } hPalette = CreatePalette(lpMem); GlobalUnlock(hMem); } GlobalFree(hMem); } } return(hPalette); } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: PaintWindow Summary: This routine is used to paint the background of a window. Borrowed from GDIDEMO in the Win32 samples of the Win32 SDK. Args: HWND hWnd, Window handle. int nColor New window color. Returns: void. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ VOID PaintWindow(HWND hWnd, int nColor) { HDC hDC; int nMapMode,idx,nSize,nReserved,nLoop; RECT rect; HBRUSH hBrush; PAINTSTRUCT ps; HPALETTE hPal; if(hDC = BeginPaint(hWnd,&ps)) { GetClientRect(hWnd,&rect); nMapMode = SetMapMode(hDC,MM_ANISOTROPIC); if(GetDeviceCaps(hDC,RASTERCAPS) & RC_PALETTE) { nReserved = GetDeviceCaps(hDC,NUMRESERVED); nSize = GetDeviceCaps(hDC,SIZEPALETTE) - nReserved; if(hPal = CreateColorScalePalette(hDC,nColor)) { hPal = SelectPalette(hDC,hPal,FALSE); RealizePalette(hDC); SetWindowExtEx(hDC,nSize,nSize,NULL); SetViewportExtEx(hDC,rect.right,-rect.bottom,NULL); SetViewportOrgEx(hDC,0,rect.bottom,NULL); nLoop = nSize >> 1; for(idx=0; idx < nLoop; idx++) { hBrush = CreateSolidBrush(PALETTEINDEX(idx+nLoop)); SetRect(&rect,idx,idx,nSize-idx,nSize-idx); FillRect(hDC,&rect,hBrush); DeleteObject(hBrush); } DeleteObject(SelectPalette(hDC,hPal,FALSE)); RealizePalette(hDC); } } else { SetWindowExtEx(hDC,512,512,NULL); SetViewportExtEx(hDC,rect.right,-rect.bottom,NULL); SetViewportOrgEx(hDC,0,rect.bottom,NULL); for(idx=0; idx < 256; idx++) { hBrush = CreateSolidBrush(RGB(0,0,idx)); SetRect(&rect,idx,idx,512-idx,512-idx); FillRect(hDC,&rect,hBrush); DeleteObject(hBrush); } } SetMapMode(hDC,nMapMode); EndPaint(hWnd,&ps); } return; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: FileExist Summary: Function to test for the existance of a file. Args: TCHAR* pszFileName String pointer to file's path/name. Returns: BOOL. TRUE if file exists; FALSE if not. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ BOOL FileExist(TCHAR* pszFileName) { BOOL bExist = FALSE; HANDLE hFile; if (NULL != pszFileName) { // Use the preferred Win32 API call and not the older OpenFile. hFile = CreateFile( pszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { // If the handle is valid then the file exists. CloseHandle(hFile); bExist = TRUE; } } return (bExist); } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: MakeFamilyPath Summary: Function to make a family file/path/name string using the detetected pathname of the current executable module. Makes paths like d:\dir1\dir2\mymodule.hlp, d:\dir1\dir2\mymodule.lic, etc. Args: HINSTANCE hInst Handle to the module intstance. TCHAR* pszNewPath String pointer to the new path/name. TCHAR* pszFileExt String pointer to the filename extension for the new path. Returns: BOOL. TRUE if success; FALSE if not. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ BOOL MakeFamilyPath( HINSTANCE hInst, TCHAR* pszNewPath, TCHAR* pszFileExt) { BOOL bOk = FALSE; TCHAR szPath[MAX_PATH]; TCHAR szDrive[64]; TCHAR szDir[MAX_PATH]; TCHAR szName[64]; if (NULL != pszNewPath) { pszNewPath[0] = 0; bOk = (0 != GetModuleFileName(hInst, szPath, MAX_PATH)); if (bOk) { _tsplitpath(szPath, szDrive, szDir, szName, NULL); lstrcpy(pszNewPath, szDrive); lstrcat(pszNewPath, szDir); lstrcat(pszNewPath, szName); lstrcat(pszNewPath, pszFileExt); } } return bOk; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: CmdExec Summary: Execute an EXE Win32 program by creating a process and running the specified EXE in it. Args: LPTSTR szCmd, Entire command line (eg, "notepad.exe mytext.txt") Returns: BOOL TRUE if succeed; FALSE if fail. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ BOOL CmdExec( LPTSTR szCmd) { BOOL bOk; STARTUPINFO si; PROCESS_INFORMATION pi; // Execute the command with a call to the CreateProcess API call. memset(&si,0,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.wShowWindow = SW_SHOW; bOk = CreateProcess(NULL,szCmd,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return bOk; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: ReadMe Summary: For use by code sample applications that study themselves as it were. This function assumes a "family" named .TXT "readme" text file is located next to the main .EXE file for the code sample. This function launches a reader/editor on that text file. The default editor\reader is NOTEPAD.EXE. You can change that editor by changing EDITOR_FILE_STR in APPUTIL.H above. Args: HINSTANCE hInst, Handle of the executable module instance. HWND hWndOwner, Handle to owner parent window. Returns: void F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ void ReadMe( HINSTANCE hInst, HWND hWndOwner) { TCHAR szReadCmd[MAX_PATH+12]; TCHAR szFileName[MAX_PATH]; BOOL bOk; int iResult; // Build a path to where the .TXT file should be (it should be in // the same directory as the .EXE but with the .TXT extension. MakeFamilyPath(hInst, szFileName, TEXT(README_FILE_EXT)); // First check if the readme .TXT file is there at all. if (FileExist(szFileName)) { // If the text file is there then assemble a command string. lstrcpy(szReadCmd, TEXT(EDITOR_FILE_STR)); lstrcat(szReadCmd, szFileName); // And execute it. bOk = CmdExec(szReadCmd); if (!bOk) { // If create procees failed then put up an error box. iResult = MessageBox( hWndOwner, TEXT(NOEDITOR_ERROR_STR), TEXT(ERROR_TITLE_STR), MB_OK | MB_ICONEXCLAMATION); } } else { // If the .TXT file doesn't exist the put up an error box. iResult = MessageBox( hWndOwner, TEXT(NOREADME_ERROR_STR), TEXT(ERROR_TITLE_STR), MB_OK | MB_ICONEXCLAMATION); } return; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: ReadMeFile Summary: For use by code sample applications that study themselves as it were. This function allows you to pass a filename for the .TXT "readme" file associated with the code sample and to launch a reader/editor on that file. The default editor\reader is NOTEPAD.EXE. You can change that editor by changing EDITOR_FILE_STR in APPUTIL.H. Args: HWND hWndOwner, Handle to owner parent window. LPTSTR szFileName, Filename string. Returns: void F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ void ReadMeFile( HWND hWndOwner, LPTSTR szFileName) { TCHAR szReadCmd[MAX_PATH+12]; BOOL bOk; int iResult; // First check if the readme .TXT file is there at all. if (FileExist(szFileName)) { // If the text file is there then assemble a command string. lstrcpy(szReadCmd, TEXT(EDITOR_FILE_STR)); lstrcat(szReadCmd, szFileName); // And execute it. bOk = CmdExec(szReadCmd); if (!bOk) { // If create procees failed then put up an error box. iResult = MessageBox( hWndOwner, TEXT(NOEDITOR_ERROR_STR), TEXT(ERROR_TITLE_STR), MB_OK | MB_ICONEXCLAMATION); } } else { // If the .TXT file doesn't exist the put up an error box. iResult = MessageBox( hWndOwner, TEXT(NOREADME_ERROR_STR), TEXT(ERROR_TITLE_STR), MB_OK | MB_ICONEXCLAMATION); } return; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: ReadSource Summary: For use by code sample applications that study themselves as it were. This function allows you to select one of the source files of this code sample and launch a reader to edit/read it. NOTEPAD.EXE is the default editor/reader. You can change this by changing EDITOR_FILE_STR in APPUTIL.H. Args: HWND hWndOwner Handle of parent window. OPENFILENAME* pofn, Pointer to the Open File Name Common Dialog structure. Returns: void F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ void ReadSource( HWND hWndOwner, OPENFILENAME* pOfn) { TCHAR szReadCmd[MAX_PATH+12]; TCHAR szFileName[MAX_PATH]; BOOL bOk; int iResult; // We'll use the OpenFileName Common Dialog (defined in main app). // Set the dialog's file filter and title. szFileName[0] = 0; pOfn->lpstrFilter = TEXT(OFN_SOURCEFILES_STR); pOfn->lpstrTitle = TEXT(OFN_SOURCETITLE_STR); pOfn->lpstrFile = szFileName; // Call up the dialog to get a file name from the user. if (GetOpenFileName(pOfn)) { // If the user provided a file name then assemble a command string lstrcpy(szReadCmd, TEXT(EDITOR_FILE_STR)); lstrcat(szReadCmd, szFileName); // And execute it. bOk = CmdExec(szReadCmd); if (!bOk) { // If create procees failed then put up an error box. iResult = MessageBox( hWndOwner, TEXT(NOEDITOR_ERROR_STR), TEXT(ERROR_TITLE_STR), MB_OK | MB_ICONEXCLAMATION); } } return; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: OutputDebugFmt Summary: Wraps the Win32 OutputDebugString API call to provide printf-style formatted (and variable argument) output. Args: LPTSTR pszFmt, Format string. [...] Arguments to match those specified in the format string. Returns: void F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ void OutputDebugFmt( LPTSTR pszFmt, ...) { va_list arglist; va_start(arglist, pszFmt); TCHAR szMsg[MAX_STRING_LENGTH]; // Use the format string and arguments to format the content text. wvsprintf(szMsg, pszFmt, arglist); // Output the newly formated message string to the debugger display. OutputDebugString(szMsg); return; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: GetErrorMsg Summary: Accepts a Win32 error code and retrieves a human readable system message for it. Args: HRESULT hr SCODE error code. LPTSTR pszMsg Pointer string where message will be placed. UINT uiSize Max size of the msg string. Returns: BOOL TRUE if hr was error; FALSE if not. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ BOOL GetErrorMsg( HRESULT hr, LPTSTR pszMsg, UINT uiSize) { BOOL bErr = FAILED(hr); DWORD dwSize; if (bErr) { memset(pszMsg, 0, uiSize * sizeof(TCHAR)); if (HRESULT_FACILITY(hr) == FACILITY_WINDOWS) hr = HRESULT_CODE(hr); dwSize = FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), pszMsg, uiSize, NULL); if (dwSize>2) { // Take out the trailing CRLF. pszMsg[--dwSize] = 0; pszMsg[--dwSize] = 0; } } return bErr; } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: WindowProc Summary: Standard WindowProc callback function that forwards Windows messages on to the CVirWindow::WindowProc method. This Window procedure expects that it will receive a "this" pointer as the lpCreateParams member passed as part of the WM_NCCREATE message. It saves the "this" pointer in the GWL_USERDATA field of the window structure. Args: HWND hWnd, Window handle. UINT uMsg, Windows message. WPARAM wParam, First message parameter (word sized). LPARAM lParam); Second message parameter (long sized). Returns: LRESULT. Windows window procedure callback return value. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Get a pointer to the window class object. CVirWindow* pWin = (CVirWindow*) GetWindowLong(hWnd, GWL_USERDATA); switch (uMsg) { case WM_NCCREATE: // Since this is the first time that we can get ahold of // a pointer to the window class object, all messages that might // have been sent before this are never seen by the Windows object // and only get passed on to the DefWindowProc // Get the initial creation pointer to the window object pWin = (CVirWindow *) ((CREATESTRUCT *)lParam)->lpCreateParams; // Set it's protected m_hWnd member variable to ensure that // member functions have access to the correct window handle. pWin->m_hWnd = hWnd; // Set its USERDATA DWORD to point to the window object SetWindowLong(hWnd, GWL_USERDATA, (long) pWin); break; case WM_DESTROY: // This is our signal to destroy the window object. SetWindowLong(hWnd, GWL_USERDATA, 0); delete pWin; pWin = (CVirWindow *) 0; break; default: break; } // Call its message proc method. if (pWin != (CVirWindow *) 0) return (pWin->WindowProc(uMsg, wParam, lParam)); else return (DefWindowProc(hWnd, uMsg, wParam, lParam)); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CVirWindow::Create Summary: Envelopes the Windows' CreateWindow call. Uses its window-creation data pointer to pass the 'this' pointer. Args: LPTSTR lpszClassName, Address of registered class name. LPTSTR lpszWindowName, Address of window name/title. DWORD dwStyle, Window style. int x, Horizontal position of window. int y, Vertical position of window. int nWidth, Window width. int nHeight, Window height. HWND hwndParent, Handle of parent or owner window. HMENU hmenu, Handle of menu, or child window identifier. HINSTANCE hinst) Handle of application instance. Modifies: m_hWnd, m_hInst. Returns: HWND (Window handle) of the created window. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ HWND CVirWindow::Create( LPTSTR lpszClassName, LPTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInst) { // Remember the passed instance handle in a member variable of the // C++ Window object. m_hInst = hInst; // Call the Win32 API to create the window. m_hWnd = ::CreateWindow( lpszClassName, lpszWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInst, this); return (m_hWnd); } /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F Function: DialogProc Summary: The general dialog procedure callback function. Used by all CVirDialog class objects. This procedure is the DialogProc registered for all dialogs created with the CVirDialog class. It uses the parameter passed with the WM_INITDIALOG message to identify the dialog classes' "this" pointer which it then stores in the window structure's GWL_USERDATA field. All subsequent messages can then be forwarded on to the correct dialog class's DialogProc method by using the pointer stored in the GWL_USERDATA field. Args: HWND hWndDlg, Handle of dialog box. UINT uMsg, Message. WPARAM wParam, First message parameter (word sized). LPARAM lParam); Second message parameter (long sized). Returns: BOOL. Return of the CVirDialog::DialogProc method. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/ BOOL CALLBACK DialogProc( HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Get a pointer to the window class object. CVirDialog* pdlg = (CVirDialog*) GetWindowLong(hWndDlg, GWL_USERDATA); switch (uMsg) { case WM_INITDIALOG: // Get a pointer to the window class object. pdlg = (CVirDialog*) lParam; // Assign the m_hWnd member variable. pdlg->m_hWnd = hWndDlg; // Set the USERDATA word to point to the class object. SetWindowLong(hWndDlg, GWL_USERDATA, (long) pdlg); break; default: break; } // Call its message proc method. if (pdlg != (CVirDialog *) 0) return (pdlg->DialogProc(hWndDlg, uMsg, wParam, lParam)); else return (FALSE); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CVirDialog::ShowDialog Summary: Creates the dialog so that it's DialogProc member function can be invoked. The dialog box object exists until deleted by the caller. It can be shown any number of times. This function is analgous to Windows' DialogBox function. The main difference being that you don't specify a DialogProc; you override the pure virtal function CVirDialog::DialogProc. Args: HINSTANCE hInst, Handle of the module instance. Needed to specify the module instance for fetching the dialog template resource (ie, from either a host EXE or DLL). LPTSTR lpszTemplate, Identifies the dialog box template. HWND hwndOwner) Handle of the owner window. Modifies: m_hInst. Returns: Return value from the DialogBoxParam Windows API function. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ int CVirDialog::ShowDialog( HINSTANCE hInst, LPTSTR lpszTemplate, HWND hWndOwner) { int iResult; // Assign the module instance handle in the Dialog object. m_hInst = hInst; // Create and show the dialog on screen. Load the dialog resource // from the specified module instance (could be a module other than // that of the EXE that is running--the resources could be in a DLL // that is calling this ShowDialog). Pass the 'this' pointer to the // dialog object so that it can be assigned inside the dialog object // during WM_INITDIALOG and later available to the dailog procedure // via the GWL_USERDATA associated with the dialog window. iResult = ::DialogBoxParam( hInst, lpszTemplate, hWndOwner, (DLGPROC)::DialogProc, (long)this); return (iResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CAboutBox::DialogProc Summary: Dialog proc for the About dialog box. This DialogProc method definition overrides the same-named pure virtual function in abstract base class CVirDialog thus giving AboutBox-unique message dispatching behavior to this derivation of CVirDialog. The remaining behavior of CAboutBox is inherited from CVirDialog and is common to all CVirDialogs. Args: HWND hWndDlg, Handle to the dialog. UINT uMsg, Windows message to dialog. WPARAM wParam, First message parameter (word sized). LPARAM lParam) Second message parameter (long sized). Modifies: . Returns: BOOL. TRUE if message was handled; FALSE otherwise. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CAboutBox::DialogProc( HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BOOL bResult = TRUE; switch (uMsg) { case WM_INITDIALOG: SetFocus(GetDlgItem(hWndDlg,IDOK)); break; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) ::EndDialog(hWndDlg, TRUE); break; case WM_PAINT: // Wash the background of the aboutbox to give it a nice // blue-scaling effect. Invalidate the OK button to force it to the // top. This seems to be necessary since the OK button gets // overwritten during the washing. PaintWindow(hWndDlg,COLOR_SCALE_BLUE); InvalidateRect(GetDlgItem(hWndDlg,IDOK),NULL,TRUE); break; default: bResult = FALSE; break; } return(bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgBox::Init Summary: CMsgBox constructor. Initializes private member data handles for both the eventual Parent window of any MsgBox and the application instance. Args: HINSTANCE hInst, Handle of app instance. HWND hWndParent) Handle of parent window. Returns: BOOL TRUE. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgBox::Init( HINSTANCE hInst, HWND hWndOwner) { m_hInst = hInst; m_hWndOwner = hWndOwner; return (TRUE); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgBox::Error Summary: Shows a specified message string in an Error MessageBox Dialog. Args: LPTSTR szMsg The message string to display. Returns: int Result of the MessageBox call. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ int CMsgBox::Error( LPTSTR szMsg) { int iResult; iResult = MessageBox( m_hWndOwner, szMsg, TEXT(ERROR_TITLE_STR), MB_OK | MB_ICONEXCLAMATION); return (iResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgBox::ErrorID Summary: Shows a resource ID specified message string in an Error MessageBox Dialog. Args: UINT uMsgID The resource ID of the message string to display. Returns: int Result of the MessageBox call. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ int CMsgBox::ErrorID( UINT uMsgID) { int iResult = FALSE; TCHAR szMsg[MAX_STRING_LENGTH]; if (LoadString(m_hInst, uMsgID, szMsg, MAX_STRING_LENGTH)) { iResult = MessageBox( m_hWndOwner, szMsg, TEXT(ERROR_TITLE_STR), MB_OK | MB_ICONEXCLAMATION); } return (iResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgBox::Note Summary: Shows a specified message string in a Notice MessageBox Dialog. Args: LPTSTR szMsg The message string to display. Returns: int Result of the MessageBox call. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ int CMsgBox::Note( LPTSTR szMsg) { int iResult; iResult = MessageBox( m_hWndOwner, szMsg, TEXT(NOTICE_TITLE_STR), MB_OK | MB_ICONINFORMATION); return (iResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgBox::NoteID Summary: Shows a resource ID specified message string in a Notice MessageBox Dialog. Args: UINT uMsgID The resource ID of the message string to display. Returns: int Result of the MessageBox call. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ int CMsgBox::NoteID( UINT uMsgID) { int iResult = FALSE; TCHAR szMsg[MAX_STRING_LENGTH]; if (LoadString(m_hInst, uMsgID, szMsg, MAX_STRING_LENGTH)) { iResult = MessageBox( m_hWndOwner, szMsg, TEXT(NOTICE_TITLE_STR), MB_OK | MB_ICONINFORMATION); } return (iResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgBox::NoteFmt Summary: Shows a printf-style formatted message string in a Notice MessageBox Dialog. Args: LPTSTR szFmtMsg The format/message string to display. [...] Arguments to match those specified in the format string. Returns: int Result of the MessageBox call. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ int CMsgBox::NoteFmt( LPTSTR szFmtMsg ...) { int iResult = 0; va_list arglist; va_start(arglist, szFmtMsg); TCHAR szMsg[MAX_STRING_LENGTH]; // Use the format string to format the messagebox's content text. wvsprintf(szMsg, szFmtMsg, arglist); iResult = MessageBox( m_hWndOwner, szMsg, TEXT(NOTICE_TITLE_STR), MB_OK | MB_ICONINFORMATION); return (iResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgBox::NoteFmtID Summary: Shows a resource ID specified printf-style formatted message string in a Notice MessageBox Dialog. Args: UINT uFmtMsgID The resource ID of the format message string to display. [...] Arguments to match those specified in the format string. Returns: int Result of the MessageBox call. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ int CMsgBox::NoteFmtID( UINT uFmtMsgID, ...) { int iResult = 0; va_list arglist; va_start(arglist, uFmtMsgID); TCHAR szFmtMsg[MAX_STRING_LENGTH]; TCHAR szMsg[MAX_STRING_LENGTH]; if (LoadString(m_hInst, uFmtMsgID, szFmtMsg, MAX_STRING_LENGTH)) { // Use the format string to format the messagebox's content text. wvsprintf(szMsg, szFmtMsg, arglist); iResult = MessageBox( m_hWndOwner, szMsg, TEXT(NOTICE_TITLE_STR), MB_OK | MB_ICONINFORMATION); } return (iResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::Create Summary: Creates the ListBox as a child window to fill the client area of the specified parent window or to exist as a separate window owned by the parent window. Args: HINSTANCE hInst, Instance handle of the application. HWND hWndparent, Window handle for the parent window of the listbox. BOOL bChild) Flag to create the listbox as a child window. TRUE means fit the child window to fill the client area of the parent window. FALSE means the window is a separate (but owned) window. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::Create( HINSTANCE hInst, HWND hWndParent, BOOL bChild) { BOOL bResult = FALSE; HWND hWnd; RECT rect; DWORD dwStyle = WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | LBS_NOSEL | LBS_NOINTEGRALHEIGHT; TCHAR* pszTitle = bChild ? NULL : TEXT("Trace Log"); dwStyle |= bChild ? WS_CHILD : WS_OVERLAPPEDWINDOW; // Logging will be flagged as on when creation is successful. m_bLogging = FALSE; if (IsWindow(hWndParent)) { GetClientRect(hWndParent, &rect); // Create the child ListBox window and fill the parent window with it. hWnd = ::CreateWindowEx( 0, // Extended Window Style TEXT("LISTBOX"), // Class Name pszTitle, // Window Title dwStyle, // The window style 0, // (x,y)=Upper left of Parent window 0, rect.right, // Width; Fill Client Window rect.bottom, // Height hWndParent, // Parent Window Handle 0, // No menu hInst, // App Instance Handle NULL); // Window Creation Data if (NULL != hWnd) { // Remember the window handle of this listbox window. m_hWndLog = hWnd; // Remember the instance of this application. m_hInstLog = hInst; // Remember if this is a child window (bChild==TRUE). m_bChild = bChild; // Turn on message logging by default after create. m_bLogging = TRUE; // Return success. bResult = TRUE; } } return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::Logging Summary: Turns logging of or off. Args: BOOL bLogging TRUE to turn on; FALSE to turn off. Returns: BOOL New logging status. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::Logging( BOOL bLogging) { BOOL bResult = bLogging; m_bLogging = bLogging; return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::Msg Summary: Logs a message string as a separate line in the listbox. Args: LPTSTR szMsg Pointer to String of the message to display/log. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::Msg( LPTSTR szMsg) { BOOL bResult = FALSE; int iIndex; if (m_bLogging) { ::SendMessage( m_hWndLog, LB_ADDSTRING, 0, (LPARAM)szMsg); iIndex = ::SendMessage( m_hWndLog, LB_GETCOUNT, 0, 0); if (LB_ERR != iIndex && iIndex > 0) { --iIndex; ::SendMessage( m_hWndLog, LB_SETCURSEL, (WPARAM)iIndex, 0); } bResult = TRUE; } #if defined(_DEBUG) ::OutputDebugString(szMsg); #endif return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::MsgFmt Summary: Logs a printf-style formated message as a separate line in the Message log listbox. Args: LPTSTR szFmtMsg The format/message string to display/log. [...] Arguments to match those specified in the format string. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::MsgFmt( LPTSTR szFmtMsg, ...) { BOOL bResult = FALSE; va_list arglist; va_start(arglist, szFmtMsg); TCHAR szMsg[MAX_STRING_LENGTH]; int iIndex; // Use the format string and arguments to format the content text. wvsprintf(szMsg, szFmtMsg, arglist); // Send the newly formated message string to the Log Listbox. if (m_bLogging) { ::SendMessage( m_hWndLog, LB_ADDSTRING, 0, (LPARAM)szMsg); iIndex = ::SendMessage( m_hWndLog, LB_GETCOUNT, 0, 0); if (LB_ERR != iIndex && iIndex > 0) { --iIndex; ::SendMessage( m_hWndLog, LB_SETCURSEL, (WPARAM)iIndex, 0); } bResult = TRUE; } #if defined(_DEBUG) ::OutputDebugString(szMsg); #endif return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::MsgID Summary: Logs a message string as a separate line in the listbox. Args: int iMsgID String Resource ID for the message to display/log. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::MsgID( int iMsgID) { BOOL bResult = FALSE; TCHAR szMsg[MAX_STRING_LENGTH]; if (LoadString(m_hInstLog, iMsgID, szMsg, MAX_STRING_LENGTH)) bResult = Msg(szMsg); return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::MsgFmtID Summary: Logs a printf-style formated message as a separate line in the Message log listbox. Args: int iFmtID The resource ID for the format/message string to display/log. [...] Arguments to match those specified in the format string. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::MsgFmtID( int iFmtID, ...) { BOOL bResult = FALSE; va_list arglist; va_start(arglist, iFmtID); TCHAR szFormat[MAX_STRING_LENGTH]; TCHAR szMsg[MAX_STRING_LENGTH]; // Load the format string from the app's string resources. if (LoadString(m_hInstLog, iFmtID, szFormat, MAX_STRING_LENGTH)) { // Use the format string and arguments to format the content text. wvsprintf(szMsg, szFormat, arglist); // Send the newly formated message string to the Log Listbox. bResult = Msg(szMsg); } return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::Resize Summary: Resizes the listbox to a new width and height. Called during the parent window's WM_SIZE to fit the listbox to the client area of the parent window. It only honors this request if it is an integral child window. Args: int nWidth New width in pixels of the listbox. int nHeight New height in pixels of the listbox. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::Resize( int nWidth, int nHeight) { BOOL bResult = FALSE; if (m_bChild) bResult = ::MoveWindow(m_hWndLog, 0, 0, nWidth, nHeight, TRUE); return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::Clear Summary: Clears all logged messages from the message log listbox. Args: void Returns: BOOL TRUE. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::Clear( void) { ::SendMessage( m_hWndLog, LB_RESETCONTENT, 0, 0); return (TRUE); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CMsgLog::Copy Summary: Copies the current content of the trace message log to the Windows clipboard. Args: void Returns: BOOL TRUE if success; FALSE if failure. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CMsgLog::Copy(void) { BOOL bResult = FALSE; DWORD iIndex; DWORD cbLen; HANDLE hClip; LPTSTR pLogData; TCHAR szLine[MAX_STRING_LENGTH]; DWORD cItems = ::SendMessage(m_hWndLog,LB_GETCOUNT,0,0); if (LB_ERR != cItems && 0 < cItems && MAX_LOG_LINES > cItems && OpenClipboard(m_hWndLog)) { if (EmptyClipboard()) { m_hLogData = GlobalAlloc(GHND, cItems * MAX_STRING_LENGTH); if (m_hLogData) { // Lock the global memory while we write to it. pLogData = (LPTSTR) GlobalLock(m_hLogData); // Loop thru the log text lines and concat them to one big string. for (iIndex = 0; iIndex < cItems; iIndex++) { // Get each log text line. cbLen = ::SendMessage( m_hWndLog, LB_GETTEXT, (WPARAM)iIndex, (LPARAM) (LPSTR)szLine); if (LB_ERR != cbLen && (MAX_STRING_LENGTH-3) > cbLen) { // Put CRLF at end. Fix this for Unicode! szLine[cbLen] = '\r'; szLine[cbLen+1] = '\n'; szLine[cbLen+2] = '\0'; if (0 == iIndex) lstrcpy((LPTSTR)pLogData, szLine); else lstrcat((LPTSTR)pLogData, szLine); } } // We're done with writing so unlock the memory block. GlobalUnlock(m_hLogData); // If there were any lines at all then copy them to clipboard. if (0 < iIndex) hClip = SetClipboardData(CF_TEXT, m_hLogData); if (!hClip) { // If we couldn't clip the data then free the global handle. GlobalFree(m_hLogData); m_hLogData = 0; } // We're done with the clipboard so close it. bResult = CloseClipboard(); } } } return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::CreateServerLog Summary: Creates the ListBox as a child window to fill the client area of the specified local server's parent window. Args: HINSTANCE hInst, Instance handle of the application. HWND hWndparent, Window handle for the parent window of the listbox. BOOL bChild) Flag to create the listbox as a child window. TRUE means fit the child window to fill the client area of the parent window. FALSE means the window is a separate (but owned) window. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::CreateServerLog( HINSTANCE hInst, HWND hWndParent, BOOL bChild) { BOOL bResult = FALSE; HWND hWnd; RECT rect; DWORD dwStyle = WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | LBS_NOSEL | LBS_NOINTEGRALHEIGHT; if (bChild) dwStyle |= WS_CHILD; else dwStyle |= WS_OVERLAPPEDWINDOW; if (IsWindow(hWndParent)) { GetClientRect(hWndParent, &rect); // Create the child ListBox window and fill the parent window with it. hWnd = ::CreateWindowEx( 0, // Extended Window Style TEXT("LISTBOX"), // Class Name NULL, // No Window Title dwStyle, // The window style 0, // (x,y)=Upper left of Parent window 0, rect.right, // Width; Fill Client Window rect.bottom, // Hight hWndParent, // Parent Window Handle 0, // No menu hInst, // App Instance Handle NULL); // Window Creation Data if (NULL != hWnd) { // Remember the instance of this application. m_hInstSender = hInst; // Remember the window handle of this Sending application. m_hWndSender = hWndParent; // Remember the window handle of the new listbox window. m_hWndListBox = hWnd; // Remember if this is a child window (bChild==TRUE). m_bChild = bChild; // Return success. bResult = TRUE; } } return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::SetClient Summary: Initialize the SendLog facility for logging to the client. Args: HINSTANCE hInstSender, Instance handle of the sending server application. HWND hWndSender, Window handle for the sending server's main window. HWND hWndReceiver, Window handle for the destination receiving client window. Returns: BOOL Returns TRUE. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::SetClient( HINSTANCE hInstSender, HWND hWndSender, HWND hWndReceiver) { BOOL bOk; bOk = (NULL != hWndReceiver); if (bOk) { // Remember the instance of this sending application. m_hInstSender = hInstSender; // Remember the main window of this sending application. m_hWndSender = hWndSender; // Remember the window handle of the receiving window. m_hWndReceiver = hWndReceiver; } return bOk; } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::LogToServer Summary: Switches logging to either server or client display. Args: BOOL bLogToServer TRUE for logging to server; FALSE for logging to client. Returns: BOOL New logging status. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::LogToServer( BOOL bLogToServer) { BOOL bResult = bLogToServer; m_bLogToServer = bLogToServer; return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::Msg Summary: Logs a message string as a separate line in the receiving CMsgLog facility. Args: LPTSTR szMsg Pointer to String of the message to display/log. Returns: BOOL bResult TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::Msg( LPTSTR szMsg) { BOOL bResult = FALSE; COPYDATASTRUCT cds; if (NULL != szMsg) { if (m_bLogToServer) { int iIndex; bResult = TRUE; ::SendMessage( m_hWndListBox, LB_ADDSTRING, 0, (LPARAM)szMsg); iIndex = ::SendMessage( m_hWndListBox, LB_GETCOUNT, 0, 0); if (LB_ERR != iIndex && iIndex > 0) { --iIndex; ::SendMessage( m_hWndListBox, LB_SETCURSEL, (WPARAM)iIndex, 0); } } else { cds.dwData = 0; cds.cbData = sizeof(TCHAR) * (lstrlen(szMsg)+1); cds.lpData = szMsg; bResult = SendMessage( m_hWndReceiver, WM_COPYDATA, (WPARAM) m_hWndSender, (LPARAM) &cds); } #if defined(_DEBUG) ::OutputDebugString(szMsg); #endif } return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::MsgFmt Summary: Logs a printf-style formated message as a separate line in the receiving CMsgLog facility. Args: LPTSTR szFmtMsg The format/message string to display/log. [...] Arguments to match those specified in the format string. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::MsgFmt( LPTSTR szFmtMsg, ...) { BOOL bResult = FALSE; va_list arglist; va_start(arglist, szFmtMsg); TCHAR szMsg[MAX_STRING_LENGTH]; if (NULL != szFmtMsg) { // Use the format string and arguments to format the content text. wvsprintf(szMsg, szFmtMsg, arglist); // Send the newly formated message string to the trace Log Listbox. bResult = Msg(szMsg); } return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::MsgID Summary: Logs a message string as a separate line in the receiving CMsgLog facility. Args: int iMsgID String Resource ID for the message to display/log. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::MsgID( int iMsgID) { BOOL bResult = FALSE; TCHAR szMsg[MAX_STRING_LENGTH]; // Load the message string from the sender's resources and log/send it. if (LoadString(m_hInstSender, iMsgID, szMsg, MAX_STRING_LENGTH)) bResult = Msg(szMsg); return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::MsgFmtID Summary: Logs a printf-style formated message as a separate line in the receiving CMsgLog facility. Args: int iFmtID The resource ID for the format/message string to display/log. [...] Arguments to match those specified in the format string. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::MsgFmtID( int iFmtID, ...) { BOOL bResult = FALSE; va_list arglist; va_start(arglist, iFmtID); TCHAR szFormat[MAX_STRING_LENGTH]; TCHAR szMsg[MAX_STRING_LENGTH]; // Load the format string from the app's string resources. if (LoadString(m_hInstSender, iFmtID, szFormat, MAX_STRING_LENGTH)) { // Use the format string and arguments to format the content text. wvsprintf(szMsg, szFormat, arglist); // Send the newly formated message string to the trace Log Listbox. bResult = Msg(szMsg); } return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::Resize Summary: Resizes the listbox to a new width and height. Called during the parent window's WM_SIZE to fit the listbox to the client area of the parent window. It only honors this request if it is an integral child window. Args: int nWidth New width in pixels of the listbox. int nHeight New height in pixels of the listbox. Returns: BOOL TRUE if successful; FALSE if not. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::Resize( int nWidth, int nHeight) { BOOL bResult = FALSE; if (m_bChild) bResult = ::MoveWindow(m_hWndListBox, 0, 0, nWidth, nHeight, TRUE); return (bResult); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::Clear Summary: Clears all logged messages from the message log listbox. Args: void Returns: BOOL TRUE. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::Clear( void) { ::SendMessage( m_hWndListBox, LB_RESETCONTENT, 0, 0); return (TRUE); } /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: CSendLog::Copy Summary: Copies the current content of the trace message log to the Windows clipboard. Args: void Returns: BOOL TRUE if success; FALSE if failure. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ BOOL CSendLog::Copy(void) { BOOL bResult = FALSE; DWORD iIndex; DWORD cbLen; HANDLE hClip; LPTSTR pLogData; TCHAR szLine[MAX_STRING_LENGTH]; DWORD cItems = ::SendMessage(m_hWndListBox,LB_GETCOUNT,0,0); if (LB_ERR != cItems && 0 < cItems && MAX_LOG_LINES > cItems && OpenClipboard(m_hWndListBox)) { if (EmptyClipboard()) { m_hLogData = GlobalAlloc(GHND, cItems * MAX_STRING_LENGTH); if (m_hLogData) { // Lock the global memory while we write to it. pLogData = (LPTSTR) GlobalLock(m_hLogData); // Loop thru the log text lines and concat them to one big string. for (iIndex = 0; iIndex < cItems; iIndex++) { // Get each log text line. cbLen = ::SendMessage( m_hWndListBox, LB_GETTEXT, (WPARAM)iIndex, (LPARAM) (LPSTR)szLine); if (LB_ERR != cbLen && (MAX_STRING_LENGTH-3) > cbLen) { // Put CRLF at end. Fix this for Unicode! szLine[cbLen] = '\r'; szLine[cbLen+1] = '\n'; szLine[cbLen+2] = '\0'; if (0 == iIndex) lstrcpy((LPTSTR)pLogData, szLine); else lstrcat((LPTSTR)pLogData, szLine); } } // We're done with writing so unlock the memory block. GlobalUnlock(m_hLogData); // If there were any lines at all then copy them to clipboard. if (0 < iIndex) hClip = SetClipboardData(CF_TEXT, m_hLogData); if (!hClip) { // If we couldn't clip the data then free the global handle. GlobalFree(m_hLogData); m_hLogData = 0; } // We're done with the clipboard so close it. bResult = CloseClipboard(); } } } return (bResult); }