///////////////////////////////////////////////////////////////////// // // Utils.cpp // // General-purpose routines that are project independent. // // HISTORY // t-danmo 96.09.22 Creation. // ///////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "progress.h" // CServiceControlProgress #include "macros.h" // MFC_TRY/MFC_CATCH USE_HANDLE_MACROS("FILEMGMT(utils.cpp)") #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // // Fusion MFC-based property page // HPROPSHEETPAGE MyCreatePropertySheetPage(AFX_OLDPROPSHEETPAGE* psp) { PROPSHEETPAGE_V3 sp_v3 = {0}; CopyMemory (&sp_v3, psp, psp->dwSize); sp_v3.dwSize = sizeof(sp_v3); return (::CreatePropertySheetPage (&sp_v3)); } ///////////////////////////////////////////////////////////////////// void ComboBox_FlushContent(HWND hwndCombo) { Assert(IsWindow(hwndCombo)); SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0); } ///////////////////////////////////////////////////////////////////// // ComboBox_FFill() // // Fill a combo box with the array of string Ids. // // Return FALSE if an error occurs (such as stringId not found). // BOOL ComboBox_FFill( const HWND hwndCombo, // IN: Handle of the combobox const TStringParamEntry rgzSPE[], // IN: SPE aray zero terminated const LPARAM lItemDataSelect) // IN: Which item to select { CString str; TCHAR szBuffer[1024]; LRESULT lResult; Assert(IsWindow(hwndCombo)); Assert(rgzSPE != NULL); for (int i = 0; rgzSPE[i].uStringId != 0; i++) { if (!::LoadString(g_hInstanceSave, rgzSPE[i].uStringId, OUT szBuffer, LENGTH(szBuffer))) { TRACE1("Unable to load string Id=%d.\n", rgzSPE[i].uStringId); Assert(FALSE && "Unable to load string"); return FALSE; } lResult = SendMessage(hwndCombo, CB_ADDSTRING, 0, reinterpret_cast(szBuffer)); Report(lResult >= 0); const WPARAM iIndex = lResult; lResult = SendMessage(hwndCombo, CB_SETITEMDATA, iIndex, rgzSPE[i].lItemData); Report(lResult != CB_ERR); if (rgzSPE[i].lItemData == lItemDataSelect) { SendMessage(hwndCombo, CB_SETCURSEL, iIndex, 0); } } // for return TRUE; } // ComboBox_FFill() ///////////////////////////////////////////////////////////////////// // ComboBox_FGetSelectedItemData() // // Get the value of the lParam field of the current selected item. // // If an error occurs return -1 (CB_ERR). // Otherwise the value of the selected item. // LPARAM ComboBox_GetSelectedItemData(HWND hwndComboBox) { LPARAM l; Assert(IsWindow(hwndComboBox)); l = SendMessage(hwndComboBox, CB_GETCURSEL, 0, 0); Report(l != CB_ERR && "Combobox has no item selected"); l = SendMessage(hwndComboBox, CB_GETITEMDATA, l, 0); Assert(l != CB_ERR && "Cannot extract item data from combobox"); if (l == CB_ERR) { Assert(CB_ERR == -1); return -1; } return l; } // ComboBox_GetSelectedItemData() ///////////////////////////////////////////////////////////////////// HWND HGetDlgItem(HWND hdlg, INT nIdDlgItem) { Assert(IsWindow(hdlg)); Assert(IsWindow(GetDlgItem(hdlg, nIdDlgItem))); return GetDlgItem(hdlg, nIdDlgItem); } // HGetDlgItem() ///////////////////////////////////////////////////////////////////// void SetDlgItemFocus(HWND hdlg, INT nIdDlgItem) { Assert(IsWindow(hdlg)); Assert(IsWindow(GetDlgItem(hdlg, nIdDlgItem))); SetFocus(GetDlgItem(hdlg, nIdDlgItem)); } ///////////////////////////////////////////////////////////////////// void EnableDlgItem(HWND hdlg, INT nIdDlgItem, BOOL fEnable) { Assert(IsWindow(hdlg)); Assert(IsWindow(GetDlgItem(hdlg, nIdDlgItem))); EnableWindow(GetDlgItem(hdlg, nIdDlgItem), fEnable); } ///////////////////////////////////////////////////////////////////// // Enable/disable one or more controls in a dialog. void EnableDlgItemGroup( HWND hdlg, // IN: Parent dialog of the controls const UINT rgzidCtl[], // IN: Group (array) of control Ids to be enabled (or disabled) BOOL fEnableAll) // IN: TRUE => We want to enable the controls; FALSE => We want to disable the controls { Assert(IsWindow(hdlg)); Assert(rgzidCtl != NULL); for (const UINT * pidCtl = rgzidCtl; *pidCtl != 0; pidCtl++) { EnableWindow(HGetDlgItem(hdlg, *pidCtl), fEnableAll); } } // EnableDlgItemGroup() ///////////////////////////////////////////////////////////////////// // Show/hide one or more controls in a dialog. void ShowDlgItemGroup( HWND hdlg, // IN: Parent dialog of the controls const UINT rgzidCtl[], // IN: Group (array) of control Ids to be shown (or hidden) BOOL fShowAll) // IN: TRUE => We want to show the controls; FALSE => We want to hide the controls { Assert(IsWindow(hdlg)); Assert(rgzidCtl != NULL); INT nCmdShow = fShowAll ? SW_SHOW : SW_HIDE; for (const UINT * pidCtl = rgzidCtl; *pidCtl != 0; pidCtl++) { ShowWindow(HGetDlgItem(hdlg, *pidCtl), nCmdShow); } } // ShowDlgItemGroup() ///////////////////////////////////////////////////////////////////// // Str_PchCopyChN() // // Copy a string until reaching character chStop or destination buffer full. // // RETURNS // Pointer to the last character of source buffer not copied into destination buffer. // This may be useful to parse the rest of the source string. // // INTERFACE NOTES // Character chStop is not copied into the destination buffer. // If cchDstMax==0, the number of characters will not be limited. // TCHAR * Str_PchCopyChN( TCHAR * szDst, // OUT: Destination buffer CONST TCHAR * szSrc, // IN: Source buffer TCHAR chStop, // IN: Character to stop the copying INT cchDstMax) // IN: Length of the output buffer { Assert(szDst != NULL); Assert(szSrc != NULL); Assert(cchDstMax >= 0); while (*szSrc != '\0' && *szSrc != chStop && --cchDstMax != 0) { *szDst++ = *szSrc++; } *szDst = '\0'; return const_cast(szSrc); } // Str_PchCopyChN() ///////////////////////////////////////////////////////////////////// // Str_SubstituteStrStr() // // Scan the source string and replace every occurrence of a // sub-string by another sub-string. This routine may // be used to count the number of sub-strings in the // source string. // // RETURNS // Return the number of subsitutions performed. // // INTERFACE NOTES // The source and destination buffer may overlap as long // as the length of the token to replace is shorter than // the token to search. // INT Str_SubstituteStrStr( TCHAR * szDst, // OUT: Destination buffer CONST TCHAR * szSrc, // IN: Source buffer CONST TCHAR * szToken, // IN: Token to find CONST TCHAR * szReplace) // IN: Token to replace { INT cSubtitutions = 0; Assert(szDst != NULL); Assert(szSrc != NULL); Assert(szToken != NULL); Assert(szReplace != NULL); Endorse(szDst == szSrc); while (*szSrc != '\0') { if (*szSrc == *szToken) { // Check if we match the token CONST TCHAR * pchSrc = szSrc; CONST TCHAR * pchToken = szToken; while (*pchToken != '\0') { if (*pchSrc++ != *pchToken++) goto TokenNotMatch; } cSubtitutions++; szSrc = pchSrc; pchSrc = szReplace; while (*pchSrc != '\0') *szDst++ = *pchSrc++; continue; TokenNotMatch: ; } // if *szDst++ = *szSrc++; } // while *szDst = '\0'; return cSubtitutions; } // Str_SubstituteStrStr() ///////////////////////////////////////////////////////////////////// // PchParseCommandLine() // // Split a command line into its path to its executable binary and // its command line arguments. The path to the executable is // copied into the output buffer. // // RETURNS // Pointer to the next character after path to the executable (Pointer // may point to an empty string). If an error occurs, return NULL. // // FORMATS SUPPORTED // 1. "c:\\winnt\\foo.exe /bar" // 2. ""c:\\winnt\\foo.exe" /bar" // The double quotes around the binary path allow // the binary path to have spaces. // TCHAR * PchParseCommandLine( CONST TCHAR szFullCommand[], // IN: Full command line TCHAR szBinPath[], // OUT: Path of the executable binary INT cchBinPathBuf) // IN: Size of the buffer { UNREFERENCED_PARAMETER (cchBinPathBuf); CONST TCHAR * pchSrc = szFullCommand; TCHAR * pchDst = szBinPath; BOOL fQuotesFound = FALSE; // TRUE => The binary path is surrounded by quotes (") Assert(szFullCommand != NULL); Assert(szBinPath != NULL); // Skip leading spaces while (*pchSrc == _T(' ')) pchSrc++; if (*pchSrc == _T('\"')) { fQuotesFound = TRUE; pchSrc++; } while (TRUE) { *pchDst = *pchSrc; if (*pchSrc == _T('\0')) break; if (*pchSrc == _T('\"') && fQuotesFound) { pchSrc++; break; } if (*pchSrc == _T(' ') && !fQuotesFound) { pchSrc++; break; } pchSrc++; pchDst++; } Assert(pchDst - szBinPath < cchBinPathBuf); *pchDst = _T('\0'); return const_cast(pchSrc); // Return character where arguments starts } // PchParseCommandLine() ///////////////////////////////////////////////////////////////////// void TrimString(CString& rString) { rString.TrimLeft(); rString.TrimRight(); } ///////////////////////////////////////////////////////////////////// // PargzpszFromPgrsz() // // Parse a group of strings into an array of pointers to strings. // This routine is somewhat similar to CommandLineToArgvW() but // uses a group of strings instead of a normal string. // // RETURN // Return a pointer to an allocated array of pointers to strings. // The array of pointers allocated with the new() operator, // therefore the caller must call ONCE delete() to free memory. // // BACKGROUND // You need to 'understand' hungarian prefixes to appreciate the // name of the function. // // p Pointer to something // psz Pointer to string terminated. // pa Pointer dynamically allocated. For instance, pasz is // a pointer to an allocated string. The allocation is // to remind the developper he/she have to free the memory // when done with the variable. // rg Array (range). Array (rg) is similar to pointer (p) // but may point to more than one element. // rgch is an array of characters while pch points to // a single character. // rgz Array of which the last element is zero. The 'last element' // may be a character, an integer, a pointer or any other // data type found in the array. // For instance rgzch would be an array of characters having // its last character zero -- a string (sz). // gr Group. This is different than array because indexing // cannot be used. For instance, a group of strings is // not the same as an array of strings. // char grsz[] = "DOS\0WfW\0Win95\0WinNT\0"; // char * rgpsz[] = { "DOS", "WfW", "Win95", "WinNT" }; // char * rgzpsz[] = { "DOS", "WfW", "Win95", "WinNT", NULL }; // // Now it is time to put all the pieces together. // pargzpsz = "pa" + "rgz" + "psz" // pgrsz = "p" + "gr" + "sz" // // USAGE // LPTSTR * pargzpsz; // pargzpsz = PargzpszFromPgrsz("DOS\0WfW\0Win95\0WinNT\0", OUT &cStringCount); // delete pargzpsz; // Single delete to free memory // LPTSTR * PargzpszFromPgrsz( CONST LPCTSTR pgrsz, // IN: Pointer to group of strings INT * pcStringCount) // OUT: OPTIONAL: Count of strings in the stored into returned value { Assert(pgrsz != NULL); Endorse(pcStringCount == NULL); // Compute how much memory is needed for allocation CONST TCHAR * pchSrc = pgrsz; INT cStringCount = 0; INT cch = sizeof(TCHAR *); while (*pchSrc != _T('\0')) { cStringCount++; for ( ; *pchSrc != _T('\0'); pchSrc++) cch++; cch = sizeof(TCHAR *) + ((cch + 4) & ~3); // Align to next DWORD pchSrc++; } // while // Allocate a single block of memory for all the data LPTSTR * pargzpsz = (LPTSTR *)new TCHAR[cch]; Assert(pargzpsz != NULL); TCHAR * pchDst = (TCHAR *)&pargzpsz[cStringCount+1]; pchSrc = pgrsz; for (INT iString = 0; iString < cStringCount; iString++) { pargzpsz[iString] = pchDst; // Copy string while (*pchSrc != '\0') { *pchDst++ = *pchSrc++; } *pchDst++ = *pchSrc++; // Copy null-terminator pchDst = (TCHAR *)(((INT_PTR)pchDst + 3) & ~3); // Align pointer to next DWORD } // for pargzpsz[cStringCount] = NULL; if (pcStringCount != NULL) *pcStringCount = cStringCount; return pargzpsz; } // PargzpszFromPgrsz() ///////////////////////////////////////////////////////////////////// void ListView_AddColumnHeaders( HWND hwndListview, // IN: Handle of the listview we want to add columns const TColumnHeaderItem rgzColumnHeader[]) // IN: Array of column header items { RECT rcClient; INT cxTotalWidth; // Total width of the listview control LV_COLUMN lvColumn; INT cxColumn; // Width of the individual column TCHAR szBuffer[1024]; Assert(IsWindow(hwndListview)); Assert(rgzColumnHeader != NULL); GetClientRect(hwndListview, OUT &rcClient); cxTotalWidth = rcClient.right; lvColumn.pszText = szBuffer; for (INT i = 0; rgzColumnHeader[i].uStringId != 0; i++) { if (!::LoadString(g_hInstanceSave, rgzColumnHeader[i].uStringId, OUT szBuffer, LENGTH(szBuffer))) { TRACE1("Unable to load string Id=%d\n", rgzColumnHeader[i].uStringId); Assert(FALSE); continue; } lvColumn.mask = LVCF_TEXT; cxColumn = rgzColumnHeader[i].nColWidth; if (cxColumn > 0) { Assert(cxColumn <= 100); cxColumn = (cxTotalWidth * cxColumn) / 100; lvColumn.mask |= LVCF_WIDTH; lvColumn.cx = cxColumn; } INT iColRet = ListView_InsertColumn(hwndListview, i, IN &lvColumn); Report(iColRet == i); } // for } // ListView_AddColumnHeaders() ///////////////////////////////////////////////////////////////////// int ListView_InsertItemEx( HWND hwndListview, // IN: Handle of the listview we want to add item CONST LV_ITEM * pLvItem) // IN: Pointer to listview item { LV_ITEM lvItemT; // Temporary variable TCHAR szT[1024]; // Temporary buffer TCHAR * pch; INT iItem; // Index of the item Assert(IsWindow(hwndListview)); Assert(pLvItem != NULL); lvItemT = *pLvItem; // Copy the whole structure lvItemT.iSubItem = 0; lvItemT.pszText = szT; // Copy until the next pch = Str_PchCopyChN(OUT szT, pLvItem->pszText, '\t', LENGTH(szT)); Assert(pch != NULL); iItem = ListView_InsertItem(hwndListview, IN &lvItemT); Report(iItem >= 0); if (*pch == '\0') return iItem; Assert(*pch == '\t'); lvItemT.mask = LVIF_TEXT; lvItemT.iItem = iItem; lvItemT.iSubItem = 1; while (*pch != '\0') { pch = Str_PchCopyChN(OUT szT, pch + 1, '\t', LENGTH(szT)); BOOL fRet = ListView_SetItem(hwndListview, IN &lvItemT); Report(fRet != FALSE); lvItemT.iSubItem++; break; } return iItem; } // ListView_InsertItemEx() ///////////////////////////////////////////////////////////////////// // Display the common dialog to get a filename. BOOL UiGetFileName( HWND hwnd, TCHAR szFileName[], // OUT: Filename we want to get INT cchBufferLength) // IN: Length of szFileName buffer { OPENFILENAME ofn; Assert(szFileName != NULL); Assert(cchBufferLength > 10); // At least 10 characters TCHAR szBufferT[2048]; ::ZeroMemory( szBufferT, sizeof(szBufferT) ); VERIFY(::LoadString(g_hInstanceSave, IDS_OPENFILE_FILTER, szBufferT, LENGTH(szBufferT))); ::ZeroMemory(OUT &ofn, sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.hInstance = g_hInstanceSave; ofn.lpstrFilter = szBufferT; ofn.nFilterIndex = 1; ofn.lpstrFile = szFileName; ofn.nMaxFile = cchBufferLength; ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY; return GetOpenFileName(&ofn); } // UiGetFileName() ///////////////////////////////////////////////////////////////////// // PaszLoadStringPrintf() // // Load a string from the resource, and format it and return // pointer allocated string. // // RETURNS // Pointer to allocated string. Must call LocalFree() when // done with string. // // INTERFACE NOTES // The format of the resource string uses %1 throuth %99 and // assumes the arguments are pointers to strings. // // If you have an argument other than a string, you can append a // printf-type within two exclamation marks. // !s! Insert a string (default) // !d! Insert a decimal integer // !u! Insert an unsigned integer // !x! Insert an hexadecimal integer // // HOW TO AVOID BUGS // To avoid bugs using this routine, I strongly suggest to include // the format of the string as part of the name of the string Id. // If you change the format of the string, you should rename // the string Id to reflect the new format. This will guarantee // the correct type and number of arguments are used. // // EXAMPLES // IDS_s_PROPERTIES = "%1 Properties" // IDS_ss_PROPERTIES = "%1 Properties on %2" // IDS_sus_SERVICE_ERROR = "Service %1 encountered error %2!u! while connecting to %3" // // HISTORY // 96.10.30 t-danmo Creation // TCHAR * PaszLoadStringPrintf( UINT wIdString, // IN: String Id va_list arglist) // IN: Arguments (if any) { Assert(wIdString != 0); TCHAR szBufferT[2048]; LPTSTR paszBuffer = NULL; // Pointer to allocated buffer. Caller must call LocalFree() to free it // Load the string from the resource VERIFY(::LoadString(g_hInstanceSave, wIdString, szBufferT, LENGTH(szBufferT))); // Format the string ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, szBufferT, 0, 0, OUT (LPTSTR)&paszBuffer, // Buffer will be allocated by FormatMessage() 0, &arglist); #ifdef DEBUG if (paszBuffer == NULL) { DWORD dw = GetLastError(); Report(FALSE && "FormatMessage() failed."); } #endif return paszBuffer; } // PaszLoadStringPrintf() ///////////////////////////////////////////////////////////////////// // LoadStringPrintf() // // Load a string from the resources, format it and copy the result string // into the CString object. // // Can also use LoadStringWithInsertions() // AFX_MANAGE_STATE(AfxGetStaticModuleState()) // // EXAMPLES // LoadStrigPrintf(IDS_s_PROPERTIES, OUT &strCaption, szServiceName); // LoadStrigPrintf(IDS_ss_PROPERTIES, OUT &strCaption, szServiceName, szMachineName); // LoadStrigPrintf(IDS_sus_SERVICE_ERROR, OUT &strMessage, szServiceName, ::GetLastError(), szMachineName); // void LoadStringPrintf( UINT wIdString, // IN: String Id CString * pString, // OUT: String to receive the characters ...) // IN: Optional arguments { Assert(wIdString != NULL); Assert(pString != NULL); va_list arglist; va_start(arglist, pString); TCHAR * paszBuffer = PaszLoadStringPrintf(wIdString, arglist); *pString = paszBuffer; // Copy the string into the CString object LocalFree(paszBuffer); } ///////////////////////////////////////////////////////////////////// // SetWindowTextPrintf() // // Load a string from the resource, format it and set the window text. // // EXAMPLE // SetWindowText(hwndStatic, IDS_s_PROPERTIES, szObjectName); // // HISTORY // 96.10.30 t-danmo Creation. Core copied from LoadStringPrintf() // void SetWindowTextPrintf(HWND hwnd, UINT wIdString, ...) { ASSERT(IsWindow(hwnd)); ASSERT(wIdString != 0); va_list arglist; va_start(arglist, wIdString); TCHAR * paszBuffer = PaszLoadStringPrintf(wIdString, arglist); if (NULL != paszBuffer) // JonN 5/30/00 PREFIX 110941 SetWindowText(hwnd, paszBuffer); // Set the text of the window LocalFree(paszBuffer); } // SetWindowTextPrintf() #ifdef SNAPIN_PROTOTYPER const TCHAR rgchHexDigits[] = _T("00112233445566778899aAbBcCdDeEfF"); const TCHAR szSpcTab[] = _T(" \t"); const TCHAR szWhiteSpaces[] = _T(" \t\n\r\f\v"); const TCHAR szDecimalDigits[] = _T("0123456789"); #ifdef UNICODE #define strchrT wcschr #else #define strchrT strchr #endif ///////////////////////////////////////////////////////////////////// // FParseInteger() // // Parse the source string pchSrc and extract // its integer value. // // RETURNS // Return TRUE if successful and set uData to integer value // of the parsed string. // If not successful (ie, illegal digit or overflow), return FALSE, // set uData to zero and set nErrCode to error found. // Field pi.pchStop is always set to the last valid character // parsed. // // INTERFACE NOTES // Fields pPI->pchSrc and pPI->nFlags are preserved during // the execution of FParseInteger(). // BOOL FParseInteger(INOUT TParseIntegerInfo * pPI) { UINT uDataT; UINT uBase; UINT iDigit; UINT cDigitParsed; // Number of digits parsed BOOL fIsNegative = FALSE; const TCHAR * pchDigit; Assert(pPI != NULL); Assert(pPI->pchSrc != NULL); pPI->pchStop = pPI->pchSrc; pPI->nErrCode = PI_errOK; // No error yet pPI->uData = 0; uBase = (pPI->nFlags & PI_mskfHexBaseOnly) ? 16 : 10; cDigitParsed = 0; // Skip leading blanks while (*pPI->pchStop ==_T(' ')) pPI->pchStop++; // Check for a minus sign if (*pPI->pchStop == _T('-')) { if (pPI->nFlags & PI_mskfNoMinusSign) { pPI->nErrCode = PI_errMinusSignFound; return FALSE; } fIsNegative = TRUE; pPI->pchStop++; } // Skip leading zeroes while (*pPI->pchStop == _T('0')) { pPI->pchStop++; cDigitParsed++; } // Look for the hexadecimal prefix (0x or 0X) if (*pPI->pchStop == _T('x') || *pPI->pchStop == _T('X')) { if ((pPI->nFlags & PI_mskfAllowHexBase) == 0) { pPI->nErrCode = PI_errInvalidInteger; return FALSE; } pPI->pchStop++; cDigitParsed = 0; uBase = 16; } // if while (*pPI->pchStop != _T('\0')) { pchDigit = wcschr(rgchHexDigits, *pPI->pchStop); if (pchDigit == NULL) { if (pPI->nFlags & PI_mskfAllowRandomTail) break; // Digit not found while random tail not allowed pPI->nErrCode = PI_errInvalidInteger; return FALSE; } // if Assert(pchDigit >= rgchHexDigits); iDigit = (pchDigit - rgchHexDigits) >> 1; Assert(iDigit <= 0x0F); if (iDigit >= uBase) { // Hex digit found while parsing a decimal string pPI->nErrCode = PI_errInvalidInteger; return FALSE; } cDigitParsed++; uDataT = pPI->uData * uBase + iDigit; if (pPI->uData > ((UINT)-1)/10 || uDataT < pPI->uData) { pPI->nErrCode = PI_errIntegerOverflow; return FALSE; } pPI->uData = uDataT; pPI->pchStop++; } // while if ((cDigitParsed == 0) && (pPI->nFlags & PI_mskfNoEmptyString)) { // Empty String found while not allowed Assert(pPI->uData == 0); pPI->nErrCode = PI_errEmptyString; return FALSE; } if (fIsNegative) { pPI->uData = -(int)pPI->uData; } if (pPI->nFlags & PI_mskfSingleEntry) { // Check if there are no more digits at the end of the string // Only spaces are allowed while (*pPI->pchStop == _T(' ')) pPI->pchStop++; if (*pPI->pchStop != _T('\0')) { pPI->nErrCode = PI_errInvalidInteger; return FALSE; } } return TRUE; } // FParseInteger() ///////////////////////////////////////////////////////////////////// // FScanf() // // Parse a formatted string and extract the values. // FScanf() behaves like the well known scanf() function but // has range checking and pattern matching. The wildcard (*) // may be substituded by "%s" with a NULL pointer. // // Return TRUE if successful, otherwise return FALSE // and set nErrCode to the error found. // // Formats supported: // %d Extract a decimal integer // %i Extract a generic integer (decimal or hexadecimal) // %u Extract an unsigned decimal integer (return error if minus sign found) // %x Force extraction of an hexadecimal integer // %s Extract a string // %v Void the spaces and tabs characters // // Note: // Fields sfi.pchSrc and sfi.nFlags are preserved during // the execution of FScanf(). // // Example: // FScanf(&sfi, "%v%s.%s", " \t foobar.txt", // OUT szName, LENGTH(szName), OUT szExt, LENGTH(szExt)); // BOOL FScanf( SCANF_INFO * pSFI, // INOUT: Control structure const TCHAR * pchFmt, // IN: Format template string ...) // OUT: scanf() arguments { va_list arglist; TParseIntegerInfo pi; Assert(pSFI != 0); Assert(pchFmt != NULL); Assert(pSFI->pchSrc != NULL); va_start(INOUT arglist, pchFmt); pSFI->pchSrcStop = pSFI->pchSrc; pSFI->nErrCode = SF_errOK; pSFI->cArgParsed = 0; while (TRUE) { switch (*pchFmt++) { case 0: // End of string return TRUE; case '%': switch (*pchFmt++) { case '%': // "%%" if (*pSFI->pchSrcStop++ != '%') { pSFI->pchSrcStop--; pSFI->nErrCode = SF_errTemplateMismatch; return FALSE; } break; case 'v': while (*pSFI->pchSrcStop == ' ' || *pSFI->pchSrcStop == '\t') pSFI->pchSrcStop++; break; case 'V': while ((*pSFI->pchSrcStop != '\0') && (strchrT(szWhiteSpaces, *pSFI->pchSrcStop) != NULL)) pSFI->pchSrcStop++; break; case 'd': // "%d" Decimal integer (signed | unsigned) case 'u': // "%u" Decimal unsigned integer case 'i': // "%i" Generic integer (decimal | hexadecimal / signed | unsigned) case 'x': // "%x" Hexadecimal integer { int * p; pi.nFlags = PI_mskfNoEmptyString | PI_mskfAllowRandomTail; switch (*(pchFmt-1)) { case 'u': pi.nFlags |= PI_mskfNoMinusSign; break; case 'i': pi.nFlags |= PI_mskfAllowHexBase; break; case 'x': pi.nFlags |= PI_mskfHexBaseOnly | PI_mskfNoMinusSign; } // switch pi.pchSrc = pSFI->pchSrcStop; if (!FParseInteger(INOUT &pi)) { pSFI->pchSrcStop = pi.pchStop; return FALSE; } // if pSFI->pchSrcStop = pi.pchStop; pSFI->cArgParsed++; p = (int *)va_arg(arglist, int *); Assert(p != NULL); *p = pi.uData; } break; // Integer case 's': // "%s" String { // To get a clean string, use the format "%v%s%v" // which will strip all the spaces and tabs around // the string. TCHAR * pchDest; // Destination buffer int cchDestMax; // Size of destination buffer TCHAR chEndScan; const TCHAR * pchEndScan = NULL; // Find out the ending character(s) if (*pchFmt == '%') { switch (*(pchFmt+1)) { case 'd': case 'u': case 'i': pchEndScan = szDecimalDigits; chEndScan = '\0'; break; case 'v': // %v pchEndScan = szSpcTab; chEndScan = *(pchFmt+2); break; case 'V': // %V pchEndScan = szWhiteSpaces; chEndScan = *(pchFmt+2); break; case '%': // %% chEndScan = '%'; default: Assert(FALSE); // Ambiguous compound format (not supported anyway!) } // switch } else { chEndScan = *pchFmt; } // if...else pSFI->cArgParsed++; pchDest = (TCHAR *)va_arg(arglist, TCHAR *); if (pchDest != NULL) { cchDestMax = va_arg(arglist, int) - 1; // Verify if the size of destination buffer // is a valid size. // Otherwise, this may be the address of the // next argument Assert(cchDestMax > 0 && cchDestMax < 5000); while (cchDestMax-- > 0) { if (*pSFI->pchSrcStop == chEndScan) break; else if (*pSFI->pchSrcStop == '\0') break; else if (pchEndScan != NULL) { if (strchrT(pchEndScan, *pSFI->pchSrcStop)) break; } // if...else // Copy the character into destination buffer *pchDest++ = *pSFI->pchSrcStop++; } *pchDest = '\0'; } // if // Skip the characters until reaching either end character while (TRUE) { if (*pSFI->pchSrcStop == chEndScan) break; else if (*pSFI->pchSrcStop == '\0') break; else if (pchEndScan != NULL) { if (strchrT(pchEndScan, *pSFI->pchSrcStop)) break; } // if...else pSFI->pchSrcStop++; } // while } break; // "%s" default: // Unknown "%?" format Assert(FALSE); pSFI->pchSrcStop--; } // switch break; // case '%' default: if (*(pchFmt-1) != *pSFI->pchSrcStop++) { pSFI->pchSrcStop--; pSFI->nErrCode = SF_errTemplateMismatch; return FALSE; } } // switch } // while return TRUE; } // FScanf() ///////////////////////////////////////////////////////////////////// // Query the a registry key of type REG_SZ without trowing an exception. // BOOL RegKey_FQueryString( HKEY hKey, LPCTSTR pszValueName, // IN: Name of the key CString& rstrKeyData) // OUT: Value (data) of registry key { Assert(hKey != NULL); Assert(pszValueName != NULL); TCHAR szBufferT[4096]; DWORD cbBufferLength = sizeof(szBufferT); DWORD dwType; DWORD dwErr; dwErr = ::RegQueryValueEx( hKey, pszValueName, 0, OUT &dwType, OUT (BYTE *)szBufferT, INOUT &cbBufferLength); if ((dwErr == ERROR_SUCCESS) && (dwType == REG_SZ)) { rstrKeyData = szBufferT; // Copy the string return TRUE; } else { rstrKeyData.Empty(); return FALSE; } } // RegKey_FQueryString() #endif // SNAPIN_PROTOTYPER DWORD DisplayNameHelper( HWND hwndParent, BSTR pszMachineName, BSTR pszServiceName, DWORD dwDesiredAccess, SC_HANDLE* phSC, BSTR* pbstrServiceDisplayName) { *phSC = ::OpenSCManager( pszMachineName, NULL, SC_MANAGER_CONNECT); if (NULL == *phSC) { DWORD dwErr = ::GetLastError(); ASSERT( NO_ERROR != dwErr ); return dwErr; } SC_HANDLE hService = ::OpenService( *phSC, pszServiceName, dwDesiredAccess | SERVICE_QUERY_CONFIG); if (NULL == hService) { DWORD dwErr = ::GetLastError(); ASSERT( NO_ERROR != dwErr ); ::CloseServiceHandle(*phSC); *phSC = NULL; return dwErr; } union { // Service config QUERY_SERVICE_CONFIG qsc; BYTE rgbBufferQsc[SERVICE_cbQueryServiceConfigMax]; }; ::ZeroMemory(&qsc, max(sizeof(qsc), sizeof(rgbBufferQsc))); DWORD cbBytesNeeded = 0; if (!::QueryServiceConfigW( hService, OUT &qsc, max(sizeof(qsc), sizeof(rgbBufferQsc)), OUT &cbBytesNeeded)) { DWORD dwErr = ::GetLastError(); ASSERT( NO_ERROR != dwErr ); ::CloseServiceHandle(hService); ::CloseServiceHandle(*phSC); *phSC = NULL; return dwErr; } *pbstrServiceDisplayName = ::SysAllocString( (qsc.lpDisplayName && qsc.lpDisplayName[0]) ? qsc.lpDisplayName : pszServiceName); if (NULL == *pbstrServiceDisplayName) { ::CloseServiceHandle(hService); ::CloseServiceHandle(*phSC); *phSC = NULL; return E_OUTOFMEMORY; } ::CloseServiceHandle(hService); return NO_ERROR; } HRESULT CStartStopHelper::StartServiceHelper( HWND hwndParent, BSTR pszMachineName, BSTR pszServiceName, DWORD dwNumServiceArgs, BSTR * lpServiceArgVectors) { MFC_TRY; if ( ( (NULL != pszMachineName) && ::IsBadStringPtr(pszMachineName,0x7FFFFFFF)) || ::IsBadStringPtr(pszServiceName,0x7FFFFFFF)) { ASSERT(FALSE); return E_POINTER; } if (0 < dwNumServiceArgs) { if (::IsBadReadPtr(lpServiceArgVectors,sizeof(lpServiceArgVectors))) { ASSERT(FALSE); return E_POINTER; } for (DWORD i = 0; i < dwNumServiceArgs; i++) { if ( (NULL != lpServiceArgVectors[i]) && ::IsBadStringPtr(lpServiceArgVectors[i],0x7FFFFFFF)) { ASSERT(FALSE); return E_POINTER; } } } SC_HANDLE hScManager = NULL; CComBSTR sbstrServiceDisplayName; DWORD dwErr = DisplayNameHelper( hwndParent, pszMachineName, pszServiceName, SERVICE_START, &hScManager, &sbstrServiceDisplayName); if (NO_ERROR != dwErr) { (void) DoServicesErrMsgBox( hwndParent, MB_OK | MB_ICONSTOP, dwErr, IDS_MSG_sss_UNABLE_TO_START_SERVICE, pszServiceName, (pszMachineName && pszMachineName[0]) ? pszMachineName : (LPCTSTR)g_strLocalMachine, L""); } else { dwErr = CServiceControlProgress::S_EStartService( hwndParent, hScManager, pszMachineName, pszServiceName, sbstrServiceDisplayName, dwNumServiceArgs, (LPCTSTR *)lpServiceArgVectors); } if (NULL != hScManager) (void) ::CloseServiceHandle( hScManager ); switch (dwErr) { case CServiceControlProgress::errUserCancelStopDependentServices: case CServiceControlProgress::errCannotInitialize: case CServiceControlProgress::errUserAbort: return S_FALSE; default: break; } return HRESULT_FROM_WIN32(dwErr); MFC_CATCH; } HRESULT CStartStopHelper::ControlServiceHelper( HWND hwndParent, BSTR pszMachineName, BSTR pszServiceName, DWORD dwControlCode) { MFC_TRY; if ( ( (NULL != pszMachineName) && ::IsBadStringPtr(pszMachineName,0x7FFFFFFF)) || ::IsBadStringPtr(pszServiceName,0x7FFFFFFF)) { ASSERT(FALSE); return E_POINTER; } SC_HANDLE hScManager = NULL; CComBSTR sbstrServiceDisplayName; DWORD dwDesiredAccess = SERVICE_USER_DEFINED_CONTROL; UINT idErrorMessageTemplate = IDS_MSG_sss_UNABLE_TO_STOP_SERVICE; // CODEWORK switch (dwControlCode) { case SERVICE_CONTROL_STOP: idErrorMessageTemplate = IDS_MSG_sss_UNABLE_TO_STOP_SERVICE; dwDesiredAccess = SERVICE_STOP; break; case SERVICE_CONTROL_PAUSE: idErrorMessageTemplate = IDS_MSG_sss_UNABLE_TO_PAUSE_SERVICE; dwDesiredAccess = SERVICE_PAUSE_CONTINUE; break; case SERVICE_CONTROL_CONTINUE: idErrorMessageTemplate = IDS_MSG_sss_UNABLE_TO_RESUME_SERVICE; dwDesiredAccess = SERVICE_PAUSE_CONTINUE; break; default: break; } DWORD dwErr = DisplayNameHelper( hwndParent, pszMachineName, pszServiceName, dwDesiredAccess, &hScManager, &sbstrServiceDisplayName); if (NO_ERROR != dwErr) { (void) DoServicesErrMsgBox( hwndParent, MB_OK | MB_ICONSTOP, dwErr, idErrorMessageTemplate, pszServiceName, (pszMachineName && pszMachineName[0]) ? pszMachineName : (LPCTSTR)g_strLocalMachine, L""); } else { dwErr = CServiceControlProgress::S_EControlService( hwndParent, hScManager, pszMachineName, pszServiceName, sbstrServiceDisplayName, dwControlCode); } if (NULL != hScManager) (void) ::CloseServiceHandle( hScManager ); switch (dwErr) { case CServiceControlProgress::errUserCancelStopDependentServices: case CServiceControlProgress::errCannotInitialize: case CServiceControlProgress::errUserAbort: return S_FALSE; default: break; } return HRESULT_FROM_WIN32(dwErr); MFC_CATCH; }