//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997-1999. // // File: N C M I S C . C P P // // Contents: Miscellaneous common code. // // Notes: Pollute this under penalty of death. // // Author: shaunco 10 Oct 1997 // //---------------------------------------------------------------------------- #include #pragma hdrstop #include "ncdebug.h" #include "ncmisc.h" #include "ncreg.h" #include "ncsvc.h" #include "ncexcept.h" #include //+--------------------------------------------------------------------------- // // Function: FInSystemSetup // // Purpose: Determines whether the machine is in GUI mode setup or not. // // Arguments: // (none) // // Returns: TRUE if in GUI mode (system) setup, FALSE if not. // // Author: danielwe 13 Jun 1997 // // Notes: The state is cached (since it can't change without a reboot) // so call as often as you like. No need to keep you're own // cached copy. // BOOL FInSystemSetup () { enum SETUP_STATE { SS_UNKNOWN = 0, // state unknown SS_NOTINSETUP, // not in setup mode SS_SYSTEMSETUP // in GUI mode setup }; static SETUP_STATE s_CachedSetupState = SS_UNKNOWN; if (SS_UNKNOWN == s_CachedSetupState) { s_CachedSetupState = SS_NOTINSETUP; // Open the setup key // HRESULT hr; HKEY hkeySetup; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Setup", KEY_READ, &hkeySetup); if (S_OK == hr) { // get the value of the setup in progress // DWORD dwSysSetup; hr = HrRegQueryDword(hkeySetup, L"SystemSetupInProgress", &dwSysSetup); if ((S_OK == hr) && dwSysSetup) { s_CachedSetupState = SS_SYSTEMSETUP; } RegCloseKey(hkeySetup); } } Assert (SS_UNKNOWN != s_CachedSetupState); return (SS_SYSTEMSETUP == s_CachedSetupState); } //+--------------------------------------------------------------------------- // // Function: GetProductFlavor // // Purpose: Returns the flavor of NT currenty running on the machine. // // Arguments: // pvReserved [in] Reserved. Must be NULL. // ppf [out] Returned flavor. // // Returns: nothing // // Author: shaunco 24 Mar 1997 // // Notes: // NOTHROW VOID GetProductFlavor ( const void* pvReserved, PRODUCT_FLAVOR* ppf) { NT_PRODUCT_TYPE Type; Assert(!pvReserved); Assert(ppf); // Assume workstation product // *ppf = PF_WORKSTATION; // Even if RtlGetProductType fails, its documented to return // NtProductWinNt. // RtlGetNtProductType (&Type); if (NtProductWinNt != Type) { *ppf = PF_SERVER; } } //+--------------------------------------------------------------------------- // // Function: HrIsNetworkingInstalled // // Purpose: Returns whether networking is installed. // // Arguments: // (none) // // Returns: S_OK if networking is installed, S_FALSE if not, Win32 error // otherwise. // // Author: danielwe 25 Jun 1997 // // Notes: To determine if networking is installed, the ProviderOrder // value of System\CurrentControlSet\Control\NetworkProvider\Order // registry key is queried. If any data is present, networking // is installed. // HRESULT HrIsNetworkingInstalled () { HRESULT hr = S_OK; HKEY hkeyProvider; DWORD cbSize = 0; DWORD dwType; extern const WCHAR c_szRegKeyCtlNPOrder[]; extern const WCHAR c_szProviderOrder[]; // open the provider key hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyCtlNPOrder, KEY_READ, &hkeyProvider); if (S_OK == hr) { // get the count in bytes of the provider order value hr = HrRegQueryValueEx(hkeyProvider, c_szProviderOrder, &dwType, (LPBYTE)NULL, &cbSize); if (S_OK == hr) { if (cbSize > 2) { // if the value was present and it contained information // then we have networking of some sorts // hr = S_OK; } else { hr = S_FALSE; } } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { hr = S_FALSE; } RegCloseKey(hkeyProvider); } TraceError("HrIsNetworkingInstalled", (hr == S_FALSE) ? S_OK : hr); return hr; } #ifdef REMOTEBOOT //+--------------------------------------------------------------------------- // // Function: HrIsRemoteBootMachine // // Purpose: Returns whether this is a remote boot client. // // Arguments: // (none) // // Returns: S_OK if it is remote boot, S_FALSE if not. // // Author: adamba 27 Mar 1998 // // Notes: Calls GetSystemInfoEx to determine whether this is a // remote boot client. // HRESULT HrIsRemoteBootMachine() { BOOL fIsRemoteBoot; BOOL ok; DWORD size = sizeof(fIsRemoteBoot); ok = GetSystemInfoEx(SystemInfoRemoteBoot, &fIsRemoteBoot, &size); Assert(ok); if (fIsRemoteBoot) { return S_OK; } else { return S_FALSE; } } #endif // defined(REMOTEBOOT) //+--------------------------------------------------------------------------- // // Function: HrRegisterOrUnregisterComObject // // Purpose: Handles registration or unregistration of one or more COM // objects contained in a DLL that supports the // DllRegisterServer or DllUnregisterServer entry points. // // Arguments: // pszDllPath [in] Path to DLL that contains COM object(s) to (un)register. // rf [in] Function to perform // // Returns: S_OK if successful, Win32 or OLE HRESULT if failure. // // Author: danielwe 6 May 1997 // // Notes: // HRESULT HrRegisterOrUnregisterComObject ( PCWSTR pszDllPath, REGISTER_FUNCTION rf) { BOOL fCoUninitialize = TRUE; HRESULT hr = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED ); if (RPC_E_CHANGED_MODE == hr) { hr = S_OK; fCoUninitialize = FALSE; } if (SUCCEEDED(hr)) { // ANSI only const CHAR c_szaRegisterFunction[] = "DllRegisterServer"; const CHAR c_szaUnregisterFunction[] = "DllUnregisterServer"; typedef HRESULT (CALLBACK *HCRET)(void); HCRET pfnRegister; HMODULE hModule; // Get a pointer the the registration function in the Dll hr = HrLoadLibAndGetProc (pszDllPath, ((RF_REGISTER == rf) ? c_szaRegisterFunction : c_szaUnregisterFunction), &hModule, reinterpret_cast(&pfnRegister)); if (S_OK == hr) { // Call the registration function hr = (*pfnRegister)(); // RAID #160109 (danielwe) 21 Apr 1998: Handle this error and // ignore it. if (RPC_E_CHANGED_MODE == hr) { hr = S_OK; } TraceError ("HrRegisterOrUnregisterComObject - " "Dll(Un)RegisterServer failed!", hr); FreeLibrary (hModule); } // Balances call to CoInitialize() above. Not harmful if CoInitialize() // was called more than once before this. if (fCoUninitialize) { CoUninitialize(); } } TraceError ("HrRegisterOrUnregisterComObject", hr); return hr; } // // Special case handling for Netbios stopping // #include // Netbios IOCTLs and netbios name #define //+--------------------------------------------------------------------------- // // Func: ScStopNetbios // // Desc: This function checks if the driver being unloaded is NETBIOS.SYS. // If so it performs some special case processing for Netbios. // // Args: none // // Return: STATUS_SUCCESS if successful, or an error status // // History: 28-Apr-98 SumitC got from VRaman // //---------------------------------------------------------------------------- DWORD ScStopNetbios() { OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING NbDeviceName; IO_STATUS_BLOCK IoStatus, StopStatus; NTSTATUS ntStatus = STATUS_SUCCESS; HANDLE NbHandle = NULL; do { // // Driver being stopped is netbios // // // 1. Open a handle to the \\Device\Netbios // RtlInitUnicodeString(&NbDeviceName, NB_DEVICE_NAME); InitializeObjectAttributes( &ObjAttr, // obj attr to initialize &NbDeviceName, // string to use OBJ_CASE_INSENSITIVE, // Attributes NULL, // Root directory NULL); // Security Descriptor ntStatus = NtCreateFile( &NbHandle, // ptr to handle GENERIC_READ|GENERIC_WRITE, // desired access &ObjAttr, // name & attributes &IoStatus, // I/O status block. NULL, // alloc size. FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE // share... | FILE_SHARE_READ | FILE_SHARE_WRITE, // ...access FILE_OPEN_IF, // create disposition 0, // ...options NULL, // EA buffer 0L // Ea buffer len ); if (!NT_SUCCESS(ntStatus)) { TraceTag(ttidError, "Failed to open file handle to Netbios device (%08lx)", ntStatus); break; } // // 2. Send a stop IOCTL to it. // ntStatus = NtDeviceIoControlFile( NbHandle, // Handle to device NULL, // Event to be signalled NULL, // No post routine NULL, // no context for post &StopStatus, // return status block IOCTL_NB_STOP, // IOCTL NULL, // No input parameters 0, NULL, // No output paramters 0 ); if (!NT_SUCCESS(ntStatus)) { TraceTag(ttidSvcCtl, "Failed to send STOP IOCTL to netbios (%08lx).", "probably means Netbios isn't running... anyway, we can't stop it", ntStatus); break; } } while (FALSE); // // 4. Close the handle just opened to the driver // if (NULL != NbHandle) { NtClose( NbHandle ); } TraceError("ScStopNetbios", HRESULT_FROM_WIN32(ntStatus)); return ntStatus; } // ---------------------------------------------------------------------- // // Function: HrEnableAndStartSpooler // // Purpose: Start spooler, enable if necessary // // Arguments: None // // Returns: S_OK on success, otherwise an error code // // Author: kumarp 19-May-98 // // Notes: // HRESULT HrEnableAndStartSpooler () { static const WCHAR c_szSpooler[] = L"Spooler"; TraceTag(ttidNetcfgBase, "entering ---> HrEnableAndStartSpooler" ); // Try to start the spooler. Need to explicitly open the service // control manager with all access first, so that in case we need to // change the start type, we have the proper permission. // CServiceManager scm; HRESULT hr = scm.HrOpen (NO_LOCK, SC_MANAGER_ALL_ACCESS); if (S_OK == hr) { hr = scm.HrStartServiceAndWait (c_szSpooler); if (HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED) == hr) { TraceTag(ttidNetcfgBase, "HrEnableAndStartSpooler: spooler is " "disabled trying to enable it..." ); // Have to lock the service controller before changing the // configuration of a service. Do so and unlock before trying to // start the service. // hr = scm.HrLock (); if (S_OK == hr) { CService svc; hr = scm.HrOpenService (&svc, c_szSpooler, NO_LOCK, SC_MANAGER_ALL_ACCESS, STANDARD_RIGHTS_REQUIRED | SERVICE_CHANGE_CONFIG); if (S_OK == hr) { hr = svc.HrSetStartType (SERVICE_DEMAND_START); } scm.Unlock (); } if (S_OK == hr) { TraceTag(ttidNetcfgBase, "HrEnableAndStartSpooler: succeeded " "in enabling spooer. Now starting..." ); hr = scm.HrStartServiceAndWait(c_szSpooler); } } } TraceError("HrEnableAndStartSpooler", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrCreateDirectoryTree // // Purpose: Creates (or ensures existence of) all directories on the path // specified in szPath. // // Arguments: // pszPath [in] Full path of one or more directories to create // (i.e. c:\this\is\a\directory\path) // psa [in] Security attributes // // Returns: S_OK if success, Win32 error code otherwise // // Author: shaunco (copied from RASUI by danielwe) 26 Jun 1998 // // Notes: // HRESULT HrCreateDirectoryTree(PWSTR pszPath, LPSECURITY_ATTRIBUTES psa) { HRESULT hr = S_OK; if (pszPath) { DWORD dwErr = ERROR_SUCCESS; // Loop through the path. // PWSTR pch; for (pch = pszPath; *pch; pch++) { // Stop at each backslash and make sure the path // is created to that point. Do this by changing the // backslash to a null-terminator, calling CreateDirecotry, // and changing it back. // if (L'\\' == *pch) { BOOL fOk; *pch = 0; fOk = CreateDirectory(pszPath, psa); *pch = L'\\'; // Any errors other than path alredy exists and we should // bail out. We also get access denied when trying to // create a root drive (i.e. c:) so check for this too. // if (!fOk) { dwErr = GetLastError(); if (ERROR_ALREADY_EXISTS == dwErr) { dwErr = ERROR_SUCCESS; } else if ((ERROR_ACCESS_DENIED == dwErr) && (pch - 1 > pszPath) && (L':' == *(pch - 1))) { dwErr = ERROR_SUCCESS; } else { break; } } } } if (ERROR_ALREADY_EXISTS == dwErr) { dwErr = ERROR_SUCCESS; } if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwErr); } } TraceError("HrCreateDirectoryTree", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrDeleteFileSpecification // // Purpose: Delete the files specified with pszFileSpec from the // directory given by pszDirectoryPath. // // Arguments: // pszFileSpec [in] File specificaion to delete. e.g. *.mdb // pszDirectoryPath [in] Directory path to delete from // // Returns: S_OK or an error code. // // Author: shaunco 4 Jun 1998 // // Notes: // HRESULT HrDeleteFileSpecification ( PCWSTR pszFileSpec, PCWSTR pszDirectoryPath) { Assert (pszFileSpec && *pszFileSpec); Assert (pszDirectoryPath && *pszDirectoryPath); HRESULT hr = S_OK; INT cchSpec = lstrlenW (pszFileSpec); INT cchDir = lstrlenW (pszDirectoryPath); // Make sure the length of the directory and filespec combined is less // than MAX_PATH before continuing. The '+1' is for the backslash // that we may add. // if (cchDir + 1 + cchSpec > MAX_PATH) { hr = HRESULT_FROM_WIN32 (ERROR_BAD_PATHNAME); } else { WCHAR szPath[MAX_PATH]; // Form the path by copying the directory and making sure it // is terminated with a backslash if needed. // lstrcpyW (szPath, pszDirectoryPath); if (cchDir && (L':' != pszDirectoryPath[cchDir - 1]) && (L'\\' != pszDirectoryPath[cchDir - 1])) { lstrcatW (szPath, L"\\"); cchDir++; } // Append the filespec to the directory and look for the first // file. lstrcatW (szPath, pszFileSpec); TraceTag (ttidNetcfgBase, "Looking to delete %S (cchDir=%u)", szPath, cchDir); WIN32_FIND_DATA FindData; HANDLE hFind = FindFirstFile (szPath, &FindData); if (INVALID_HANDLE_VALUE != hFind) { PCWSTR pszFileName; INT cchFileName; do { // Skip files with these attributes. // if (FindData.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)) { continue; } // Use the shortname where possible to give us a chance // of using a path within MAX_PATH first. // pszFileName = FindData.cAlternateFileName; cchFileName = lstrlenW (pszFileName); if (!cchFileName) { pszFileName = FindData.cFileName; cchFileName = lstrlenW (pszFileName); } // If the length of the directory and filename don't exceed // MAX_PATH, form the full pathname and delete it. // if (cchDir + cchFileName < MAX_PATH) { lstrcpyW (&szPath[cchDir], pszFileName); TraceTag (ttidNetcfgBase, "Deleting %S", szPath); if (!DeleteFile (szPath)) { hr = HrFromLastWin32Error (); TraceError ("DeleteFile failed. Ignoring.", hr); } } } while (FindNextFile (hFind, &FindData)); // FindNextFile should set last error to ERROR_NO_MORE_FILES // on a succesful termination. // hr = HrFromLastWin32Error (); if (HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr) { hr = S_OK; } FindClose (hFind); } else { // If FindFirstFile didn't find anything, that's okay. // hr = HrFromLastWin32Error (); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { hr = S_OK; } } } TraceError ("HrDeleteFileSpecification", hr); return hr; } // ---------------------------------------------------------------------- // // Function: HrDeleteDirectory // // Purpose: Recursively delete a directory and its all sub-dirs. // // Arguments: // pszDir [in] full path to a dir // fContinueOnError [in] whether to continue deleting others when we // error when deleting one // // Returns: S_OK on success, otherwise an error code // // Author: kumarp 19-December-97 // danielwe 15-December-98 (moved to common and revised) // // Notes: // HRESULT HrDeleteDirectory(IN PCWSTR pszDir, IN BOOL fContinueOnError) { HRESULT hr = S_OK; WCHAR szPrefix[MAX_PATH]; WCHAR szFileSpec[MAX_PATH]; WCHAR szAllFiles[MAX_PATH]; HANDLE hFileContext; WIN32_FIND_DATA fd; TraceTag(ttidNetcfgBase, "Deleting directory %S", pszDir); lstrcpyW(szPrefix, pszDir); lstrcatW(szPrefix, L"\\"); lstrcpyW(szAllFiles, pszDir); lstrcatW(szAllFiles, L"\\"); lstrcatW(szAllFiles, L"*"); hFileContext = FindFirstFile(szAllFiles, &fd); if (hFileContext != INVALID_HANDLE_VALUE) { do { lstrcpyW(szFileSpec, szPrefix); lstrcatW(szFileSpec, fd.cFileName); if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (!(!lstrcmpiW(fd.cFileName, L".") || !lstrcmpiW(fd.cFileName, L".."))) { hr = HrDeleteDirectory(szFileSpec, fContinueOnError); if (FAILED(hr) && fContinueOnError) { hr = S_OK; } } } else { TraceTag(ttidNetcfgBase, "Deleting file %S", szFileSpec); if (DeleteFile(szFileSpec)) { hr = S_OK; } else { TraceTag(ttidNetcfgBase, "Error deleting file %S", szFileSpec); TraceError("HrDeleteDirectory", hr); hr = fContinueOnError ? S_OK : HrFromLastWin32Error(); } } if ((S_OK == hr) && FindNextFile(hFileContext, &fd)) { hr = S_OK; } else { hr = HrFromLastWin32Error(); } } while (S_OK == hr); if (hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) { hr = S_OK; } FindClose(hFileContext); if (S_OK == hr) { if (RemoveDirectory(pszDir)) { hr = S_OK; } else { TraceTag(ttidNetcfgBase, "Error deleting directory %S", pszDir); TraceLastWin32Error("HrDeleteDirectory"); hr = fContinueOnError ? S_OK : HrFromLastWin32Error(); } } } else { hr = HrFromLastWin32Error(); } TraceError("HrDeleteDirectory", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: LowerCaseComputerName // // Purpose: Utility function to lowercase a name obtained either from // the user via an UPPERCASE edit control, or via GetComputerName. // // Arguments: // szName [in,out] Computername, which is modified in-place // // Returns: VOID // // Author: SumitC 29 Sep 1999 // // Notes: The conversion only fails if CharLowerBuffW fails. Per the user // guys, CharLowerBuff never actually returns any indication of // failure, so we can't tell anyway. I've been assured that the // conversion is VERY unlikely to fail. // VOID LowerCaseComputerName( IN OUT PWSTR szName) { // try the conversion Assert(szName); DWORD dwLen = wcslen(szName); DWORD dwConverted = CharLowerBuff(szName, dwLen); Assert(dwConverted == dwLen); } void __cdecl nc_trans_func( unsigned int uSECode, EXCEPTION_POINTERS* pExp ) { throw NC_SEH_Exception( uSECode ); } void EnableCPPExceptionHandling() { _set_se_translator(nc_trans_func); } void DisableCPPExceptionHandling() { _set_se_translator(NULL); }