windows-nt/Source/XPSP1/NT/admin/cys/win32/common.cpp
2020-09-26 16:20:57 +08:00

1014 lines
20 KiB
C++

// Copyright (c) 1997-2001 Microsoft Corporation
//
// File: common.cpp
//
// Synopsis: Commonly used functions
//
// History: 02/03/2001 JeffJon Created
#include "pch.h"
#include "resource.h"
#include <ciodm.h>
// Creates the fonts for setLargeFonts().
//
// hDialog - handle to a dialog to be used to retrieve a device
// context.
//
// bigBoldFont - receives the handle of the big bold font created.
void
InitFonts(
HWND hDialog,
HFONT& bigBoldFont)
{
ASSERT(Win::IsWindow(hDialog));
HRESULT hr = S_OK;
do
{
NONCLIENTMETRICS ncm;
memset(&ncm, 0, sizeof(ncm));
ncm.cbSize = sizeof(ncm);
hr = Win::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
BREAK_ON_FAILED_HRESULT(hr);
LOGFONT bigBoldLogFont = ncm.lfMessageFont;
bigBoldLogFont.lfWeight = FW_BOLD;
String fontName = String::load(IDS_BIG_BOLD_FONT_NAME);
// ensure null termination 260237
memset(bigBoldLogFont.lfFaceName, 0, LF_FACESIZE * sizeof(TCHAR));
size_t fnLen = fontName.length();
fontName.copy(
bigBoldLogFont.lfFaceName,
// don't copy over the last null
min(LF_FACESIZE - 1, fnLen));
unsigned fontSize = 0;
String::load(IDS_BIG_BOLD_FONT_SIZE).convert(fontSize);
ASSERT(fontSize);
HDC hdc = 0;
hr = Win::GetDC(hDialog, hdc);
BREAK_ON_FAILED_HRESULT(hr);
bigBoldLogFont.lfHeight =
- ::MulDiv(
static_cast<int>(fontSize),
Win::GetDeviceCaps(hdc, LOGPIXELSY),
72);
hr = Win::CreateFontIndirect(bigBoldLogFont, bigBoldFont);
BREAK_ON_FAILED_HRESULT(hr);
Win::ReleaseDC(hDialog, hdc);
}
while (0);
}
void
SetControlFont(HWND parentDialog, int controlID, HFONT font)
{
ASSERT(Win::IsWindow(parentDialog));
ASSERT(controlID);
ASSERT(font);
HWND control = Win::GetDlgItem(parentDialog, controlID);
if (control)
{
Win::SetWindowFont(control, font, true);
}
}
void
SetLargeFont(HWND dialog, int bigBoldResID)
{
ASSERT(Win::IsWindow(dialog));
ASSERT(bigBoldResID);
static HFONT bigBoldFont = 0;
if (!bigBoldFont)
{
InitFonts(dialog, bigBoldFont);
}
SetControlFont(dialog, bigBoldResID, bigBoldFont);
}
bool
IsServiceInstalledHelper(const wchar_t* serviceName)
{
LOG_FUNCTION2(IsServiceInstalledHelper, serviceName);
ASSERT(serviceName);
// if we can open the service, then it is installed
bool result = false;
SC_HANDLE hsc =
::OpenSCManager(0, SERVICES_ACTIVE_DATABASE, GENERIC_READ);
if (hsc)
{
SC_HANDLE hs = ::OpenServiceW(hsc, serviceName, GENERIC_READ);
if (hs)
{
::CloseServiceHandle(hs);
result = true;
}
::CloseServiceHandle(hsc);
}
return result;
}
// Wait for a handle to become signalled, or a timeout to expire, or WM_QUIT
// to appear in the message queue. Pump the message queue while we wait.
//
// WARNING: UI should diable itself before calling any function that invokes
// this function, or functions calling this one should guard against
// re-entrance. Otherwise there will be a re-entrancy problem.
//
// e.g. command handler gets button clicked message, calls a func that calls
// this wait function, then user clicks the button again, command handler call
// a func that calls this one, and so on.
DWORD
MyWaitForSendMessageThread(HANDLE hThread, DWORD dwTimeout)
{
LOG_FUNCTION(MyWaitForSendMessageThread);
ASSERT(hThread);
MSG msg;
DWORD dwRet;
DWORD dwEnd = GetTickCount() + dwTimeout;
bool quit = false;
// We will attempt to wait up to dwTimeout for the thread to
// terminate
do
{
dwRet = MsgWaitForMultipleObjects(1, &hThread, FALSE,
dwTimeout, QS_ALLEVENTS | QS_SENDMESSAGE );
if (dwRet == (WAIT_OBJECT_0 + 1))
{
// empty out the message queue. We call DispatchMessage to
// ensure that we still process the WM_PAINT messages.
// DANGER: Make sure that the CYS UI is completely disabled
// or there will be re-entrancy problems here
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
// Need to re-post this so that we know to close CYS
::PostMessage(msg.hwnd, WM_QUIT, 0, 0);
quit = true;
break;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
// Calculate if we have any more time left in the timeout to
// wait on.
if (dwTimeout != INFINITE)
{
dwTimeout = dwEnd - GetTickCount();
if ((long)dwTimeout <= 0)
{
// No more time left, fail with WAIT_TIMEOUT
dwRet = WAIT_TIMEOUT;
}
}
}
// dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED
// The thread must have exited, so we are happy
//
// dwRet == WAIT_TIMEOUT
// The thread is taking too long to finish, so just
// return and let the caller kill it
} while (dwRet == (WAIT_OBJECT_0 + 1) && !quit);
return(dwRet);
}
HRESULT
CreateAndWaitForProcess(const String& commandLine, DWORD& exitCode)
{
LOG_FUNCTION2(CreateAndWaitForProcess, commandLine);
ASSERT(!commandLine.empty());
exitCode = 0;
HRESULT hr = S_OK;
do
{
PROCESS_INFORMATION procInfo;
memset(&procInfo, 0, sizeof(procInfo));
STARTUPINFO startup;
memset(&startup, 0, sizeof(startup));
String commandLine2(commandLine);
LOG(L"Calling CreateProcess");
LOG(commandLine2);
hr =
Win::CreateProcess(
commandLine2,
0,
0,
false,
0,
0,
String(),
startup,
procInfo);
BREAK_ON_FAILED_HRESULT(hr);
ASSERT(procInfo.hProcess);
DWORD dwRet = MyWaitForSendMessageThread(procInfo.hProcess, INFINITE);
ASSERT(dwRet == WAIT_OBJECT_0);
hr = Win::GetExitCodeProcess(procInfo.hProcess, exitCode);
BREAK_ON_FAILED_HRESULT(hr);
Win::CloseHandle(procInfo.hThread);
Win::CloseHandle(procInfo.hProcess);
}
while (0);
LOG(String::format(L"exit code = %1!x!", exitCode));
LOG_HRESULT(hr);
return hr;
}
HRESULT
MyCreateProcess(const String& commandLine)
{
LOG_FUNCTION2(MyCreateProcess, commandLine);
ASSERT(!commandLine.empty());
HRESULT hr = S_OK;
do
{
PROCESS_INFORMATION procInfo;
memset(&procInfo, 0, sizeof(procInfo));
STARTUPINFO startup;
memset(&startup, 0, sizeof(startup));
String commandLine2(commandLine);
LOG(L"Calling CreateProcess");
LOG(commandLine2);
hr =
Win::CreateProcess(
commandLine2,
0,
0,
false,
0,
0,
String(),
startup,
procInfo);
BREAK_ON_FAILED_HRESULT(hr);
ASSERT(procInfo.hProcess);
Win::CloseHandle(procInfo.hThread);
Win::CloseHandle(procInfo.hProcess);
}
while (0);
LOG_HRESULT(hr);
return hr;
}
bool
IsKeyValuePresent(RegistryKey& key, const String& valueKey)
{
LOG_FUNCTION(IsKeyValuePresent);
bool result = false;
do
{
String value;
HRESULT hr = key.GetValue(valueKey, value);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to read regkey %1 because: hr = %2!x!",
valueKey,
hr));
break;
}
if (!value.empty())
{
result = true;
break;
}
} while (false);
LOG_BOOL(result);
return result;
}
bool
GetRegKeyValue(
const String& keyName,
const String& value,
String& resultString,
HKEY parentKey)
{
LOG_FUNCTION(GetRegKeyValue);
bool result = true;
do
{
HRESULT hr = S_OK;
RegistryKey key;
hr = key.Open(parentKey, keyName);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to open regkey %1 because: hr = %2!x!",
keyName.c_str(),
hr));
result = false;
break;
}
hr = key.GetValue(value, resultString);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to read regkey %1 because: hr = %2!x!",
value.c_str(),
hr));
result = false;
break;
}
LOG(String::format(
L"Value of key: %1",
resultString.c_str()));
} while (false);
LOG_BOOL(result);
return result;
}
bool
GetRegKeyValue(
const String& keyName,
const String& value,
DWORD& resultValue,
HKEY parentKey)
{
LOG_FUNCTION(GetRegKeyValue);
bool result = true;
do
{
HRESULT hr = S_OK;
RegistryKey key;
hr = key.Open(parentKey, keyName);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to open regkey %1 because: hr = %2!x!",
keyName.c_str(),
hr));
result = false;
break;
}
hr = key.GetValue(value, resultValue);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to read regkey %1 because: hr = %2!x!",
value.c_str(),
hr));
result = false;
break;
}
LOG(String::format(
L"Key value: %1!d!",
resultValue));
} while (false);
LOG_BOOL(result);
return result;
}
bool
SetRegKeyValue(
const String& keyName,
const String& value,
const String& newString,
HKEY parentKey,
bool create
)
{
LOG_FUNCTION(SetRegKeyValue);
bool result = true;
do
{
HRESULT hr = S_OK;
RegistryKey key;
if (create)
{
hr = key.Create(parentKey, keyName);
}
else
{
hr = key.Open(parentKey, keyName, KEY_ALL_ACCESS);
}
if (FAILED(hr))
{
LOG(String::format(
L"Failed to open regkey %1 because: hr = %2!x!",
keyName.c_str(),
hr));
result = false;
break;
}
hr = key.SetValue(value, newString);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to write regkey %1 because: hr = %2!x!",
value.c_str(),
hr));
result = false;
break;
}
} while (false);
LOG_BOOL(result);
return result;
}
bool
SetRegKeyValue(
const String& keyName,
const String& value,
DWORD newValue,
HKEY parentKey,
bool create)
{
LOG_FUNCTION(SetRegKeyValue);
bool result = true;
do
{
HRESULT hr = S_OK;
RegistryKey key;
if (create)
{
hr = key.Create(parentKey, keyName);
}
else
{
hr = key.Open(parentKey, keyName, KEY_WRITE);
}
if (FAILED(hr))
{
LOG(String::format(
L"Failed to open regkey %1 because: hr = %2!x!",
keyName.c_str(),
hr));
result = false;
break;
}
hr = key.SetValue(value, newValue);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to write regkey %1 because: hr = %2!x!",
value.c_str(),
hr));
result = false;
break;
}
} while (false);
LOG_BOOL(result);
return result;
}
bool
IsIndexingServiceOn()
{
LOG_FUNCTION(IsIndexingServiceOn);
bool result = false;
do
{
CLSID clsid;
HRESULT hr = CLSIDFromProgID( L"Microsoft.ISAdm", &clsid );
if (FAILED(hr))
{
LOG(String::format(
L"Failed to get the CLSID from ProgID: hr = 0x%x",
hr));
break;
}
SmartInterface<IAdminIndexServer> adminIndexServer;
hr = adminIndexServer.AcquireViaCreateInstance(
clsid,
0,
CLSCTX_INPROC_SERVER);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to CoCreateInstance of IAdminIndexServer: hr = 0x%x",
hr));
break;
}
VARIANT_BOOL var;
hr = adminIndexServer->IsRunning(&var);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to get running state: hr = 0x%x",
hr));
break;
}
result = var ? true : false;
} while (false);
LOG_BOOL(result);
return result;
}
HRESULT
ModifyIndexingService(bool turnOn)
{
LOG_FUNCTION2(
ModifyIndexingService,
turnOn ? L"true" : L"false");
HRESULT hr = S_OK;
do
{
CLSID clsid;
hr = CLSIDFromProgID( L"Microsoft.ISAdm", &clsid );
if (FAILED(hr))
{
LOG(String::format(
L"Failed to get the CLSID from ProgID: hr = 0x%x",
hr));
break;
}
SmartInterface<IAdminIndexServer> adminIndexServer;
hr = adminIndexServer.AcquireViaCreateInstance(
clsid,
0,
CLSCTX_INPROC_SERVER);
if (FAILED(hr))
{
LOG(String::format(
L"Failed to CoCreateInstance of IAdminIndexServer: hr = 0x%x",
hr));
break;
}
if (turnOn)
{
hr = adminIndexServer->Start();
}
else
{
hr = adminIndexServer->Stop();
}
if (FAILED(hr))
{
LOG(String::format(
L"Failed to start or stop indexing service: hr = 0x%x",
hr));
break;
}
} while (false);
LOG(String::format(L"hr = %1!x!", hr));
return hr;
}
HRESULT
StartIndexingService()
{
return ModifyIndexingService(true);
}
HRESULT
StopIndexingService()
{
return ModifyIndexingService(false);
}
// return true if the name is a reserved name, false otherwise. If true, also
// set message to an error message describing the problem.
bool
IsReservedDnsName(const String& dnsName, String& message)
{
LOG_FUNCTION2(IsReservedDnsName, dnsName);
ASSERT(!dnsName.empty());
message.erase();
bool result = false;
// We're still trying to decide if we should restrict these names
//
// // names with these as the last labels are illegal.
//
// static const String RESERVED[] =
// {
// L"in-addr.arpa",
// L"ipv6.int",
//
// // RFC 2606 documents these:
//
// L"test",
// L"example",
// L"invalid",
// L"localhost",
// L"example.com",
// L"example.org",
// L"example.net"
// };
//
// String name(dnsName);
// name.to_upper();
// if (name[name.length() - 1] == L'.')
// {
// // remove the trailing dot
//
// name.resize(name.length() - 1);
// }
//
// for (int i = 0; i < sizeof(RESERVED) / sizeof(String); ++i)
// {
// String res = RESERVED[i];
// res.to_upper();
//
// size_t pos = name.rfind(res);
//
// if (pos == String::npos)
// {
// continue;
// }
//
// if (pos == 0 && name.length() == res.length())
// {
// ASSERT(name == res);
//
// result = true;
// message =
// String::format(
// IDS_RESERVED_NAME,
// dnsName.c_str());
// break;
// }
//
// if ((pos == name.length() - res.length()) && (name[pos - 1] == L'.'))
// {
// // the name has reserved as a suffix.
//
// result = true;
// message =
// String::format(
// IDS_RESERVED_NAME_SUFFIX,
// dnsName.c_str(),
// RESERVED[i].c_str());
// break;
// }
// }
return result;
}
bool
ValidateDomainDnsNameSyntax(
HWND dialog,
int editResID,
bool warnOnNonRFC,
bool* isNonRFC)
{
return
ValidateDomainDnsNameSyntax(
dialog,
String(),
editResID,
warnOnNonRFC,
isNonRFC);
}
bool
ValidateDomainDnsNameSyntax(
HWND dialog,
const String& domainName,
int editResID,
bool warnOnNonRFC,
bool* isNonRFC)
{
LOG_FUNCTION(ValidateDomainDnsNameSyntax);
ASSERT(Win::IsWindow(dialog));
ASSERT(editResID > 0);
bool valid = false;
String message;
String dnsName =
domainName.empty()
? Win::GetTrimmedDlgItemText(dialog, editResID)
: domainName;
if (isNonRFC)
{
*isNonRFC = false;
}
LOG(L"validating " + dnsName);
switch (
Dns::ValidateDnsNameSyntax(
dnsName,
DNS_DOMAIN_NAME_MAX_LIMIT_DUE_TO_POLICY_UTF8) )
{
case Dns::NON_RFC:
{
if (isNonRFC)
{
*isNonRFC = true;
}
if (warnOnNonRFC)
{
// warn about non-rfc names
String msg = String::format(IDS_NON_RFC_NAME, dnsName.c_str());
popup.Info(
dialog,
msg);
LOG(msg);
}
// fall through
//lint -e616 allow fall thru
}
case Dns::VALID:
{
valid = !IsReservedDnsName(dnsName, message);
break;
}
case Dns::TOO_LONG:
{
message =
String::format(
IDS_DNS_NAME_TOO_LONG,
dnsName.c_str(),
DNS_DOMAIN_NAME_MAX_LIMIT_DUE_TO_POLICY,
DNS_DOMAIN_NAME_MAX_LIMIT_DUE_TO_POLICY_UTF8);
break;
}
case Dns::NUMERIC:
case Dns::BAD_CHARS:
case Dns::INVALID:
default:
{
message =
String::format(
IDS_BAD_DNS_SYNTAX,
dnsName.c_str(),
Dns::MAX_LABEL_LENGTH);
break;
}
}
if (!valid)
{
popup.Gripe(dialog, editResID, message);
}
return valid;
}
bool
ConfirmNetbiosLookingNameIsReallyDnsName(HWND parentDialog, int editResID)
{
ASSERT(Win::IsWindow(parentDialog));
ASSERT(editResID > 0);
// check if the name is a single DNS label (a single label with a trailing
// dot does not count. If the user is DNS-saavy enough to use an absolute
// DNS name, then we will pester him no further.)
String domain = Win::GetTrimmedDlgItemText(parentDialog, editResID);
if (domain.find(L'.') == String::npos)
{
// no dot found: must be a single label
if (
popup.MessageBox(
parentDialog,
String::format(
IDS_CONFIRM_NETBIOS_LOOKING_NAME,
domain.c_str(),
domain.c_str()),
MB_YESNO) == IDNO)
{
// user goofed. or we frightened them.
HWND edit = Win::GetDlgItem(parentDialog, editResID);
Win::SendMessage(edit, EM_SETSEL, 0, -1);
Win::SetFocus(edit);
return false;
}
}
return true;
}
HRESULT
VariantArrayToStringList(VARIANT* variant, StringList& stringList)
{
LOG_FUNCTION(VariantArrayToStringList);
ASSERT(variant);
ASSERT(V_VT(variant) == (VT_ARRAY | VT_BSTR));
HRESULT hr = S_OK;
stringList.clear();
SAFEARRAY* psa = V_ARRAY(variant);
do
{
ASSERT(psa);
ASSERT(psa != (SAFEARRAY*)-1);
if (!psa or psa == (SAFEARRAY*)-1)
{
LOG(L"variant not safe array");
break;
}
if (::SafeArrayGetDim(psa) != 1)
{
LOG(L"safe array: wrong number of dimensions");
break;
}
VARTYPE vt = VT_EMPTY;
hr = ::SafeArrayGetVartype(psa, &vt);
if (FAILED(hr) || vt != VT_BSTR)
{
LOG(L"safe array: wrong element type");
break;
}
long lower = 0;
long upper = 0;
hr = ::SafeArrayGetLBound(psa, 1, &lower);
if (FAILED(hr))
{
LOG(L"can't get lower bound");
break;
}
hr = ::SafeArrayGetUBound(psa, 1, &upper);
if (FAILED(hr))
{
LOG(L"can't get upper bound");
break;
}
for (long i = lower; i <= upper; ++i)
{
BSTR item;
hr = ::SafeArrayGetElement(psa, &i, &item);
if (FAILED(hr))
{
LOG(String::format(L"index %1!d! failed", i));
continue;
}
if (item)
{
stringList.push_back(String(item));
}
::SysFreeString(item);
}
}
while (0);
LOG_HRESULT(hr);
return hr;
}