// 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 // 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(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 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 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; }