mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1315 lines
33 KiB
1315 lines
33 KiB
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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<LPARAM>(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<TCHAR *>(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<TCHAR *>(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;
|
|
}
|