/*++ Copyright (c) 2000 Microsoft Corporation Module Name: opk.c Abstract: Common modules shared by OPK tools. Note: Source Depot requires that we publish the .h (E:\NT\admin\published\ntsetup) and .lib (E:\NT\public\internal\admin\lib). Author: Brian Ku (briank) 06/20/2000 Revision History: 7/00 - Jason Cohen (jcohen) Added in the rest of the common APIs form Millennium (need for lfnbk). --*/ // // Include file(s) // #include #include #include // // External Function(s): // LPTSTR AllocateString(HINSTANCE hInstance, UINT uID) { // ISSUE-2002/02/26-acosma - This sets a restriction of 256 characters on the buffer. // TCHAR szBuffer[256]; LPTSTR lpBuffer = NULL; // Load the string from the resource and then allocate // a buffer just big enough for it. Strings can exceed 256 characters. // if ( ( LoadString(hInstance, uID, szBuffer, sizeof(szBuffer) / sizeof(TCHAR)) ) && ( lpBuffer = (LPTSTR) MALLOC(sizeof(TCHAR) * (lstrlen(szBuffer) + 1)) ) ) { lstrcpy(lpBuffer, szBuffer); } // Return the allocated buffer, or NULL if there was an error. // return lpBuffer; } LPTSTR AllocateExpand(LPTSTR lpszBuffer) { LPTSTR lpszExpanded = NULL; DWORD cbExpanded; // First we need to get the size of the expanded buffer and // allocate it. // if ( ( cbExpanded = ExpandEnvironmentStrings(lpszBuffer, NULL, 0) ) && ( lpszExpanded = (LPTSTR) MALLOC(cbExpanded * sizeof(TCHAR)) ) ) { // Now expand out the buffer. // if ( ( 0 == ExpandEnvironmentStrings(lpszBuffer, lpszExpanded, cbExpanded) ) || ( NULLCHR == *lpszExpanded ) ) { FREE(lpszExpanded); } } // Return the allocated buffer, or NULL if there was an error // or nothing in the string. // return lpszExpanded; } LPTSTR AllocateStrRes(HINSTANCE hInstance, LPSTRRES lpsrTable, DWORD cbTable, LPTSTR lpString, LPTSTR * lplpReturn) { LPSTRRES lpsrSearch = lpsrTable; LPTSTR lpReturn = NULL; BOOL bFound; // Init this return value. // if ( lplpReturn ) *lplpReturn = NULL; // Try to find the friendly name for this string in our table. // while ( ( bFound = ((DWORD) (lpsrSearch - lpsrTable) < cbTable) ) && ( lstrcmpi(lpString, lpsrSearch->lpStr) != 0 ) ) { lpsrSearch++; } // If it was found, allocate the friendly name from the resource. // if ( bFound ) { lpReturn = AllocateString(hInstance, lpsrSearch->uId); if ( lplpReturn ) *lplpReturn = lpsrSearch->lpStr; } return lpReturn; } int MsgBoxLst(HWND hwndParent, LPTSTR lpFormat, LPTSTR lpCaption, UINT uType, va_list lpArgs) { INT nReturn; DWORD dwCount = 0; LPTSTR lpText = NULL; // The format string is required. // if ( lpFormat ) { do { // Allocate 1k of characters at a time. // dwCount += 1024; // Free the previous buffer, if there was one. // FREE(lpText); // Allocate a new buffer. // if ( lpText = MALLOC(dwCount * sizeof(TCHAR)) ) nReturn = _vsntprintf(lpText, dwCount, lpFormat, lpArgs); else nReturn = 0; } while ( nReturn < 0 ); // Make sure we have the format string. // if ( lpText ) { // Display the message box. // nReturn = MessageBox(hwndParent, lpText, lpCaption, uType); FREE(lpText); } } else nReturn = 0; // Return the return value of the MessageBox() call. If there was a memory // error, 0 will be returned. // return nReturn; } int MsgBoxStr(HWND hwndParent, LPTSTR lpFormat, LPTSTR lpCaption, UINT uType, ...) { va_list lpArgs; // Initialize the lpArgs parameter with va_start(). // va_start(lpArgs, uType); // Return the return value of the MessageBox() call. If there was a memory // error, 0 will be returned. This is all // return MsgBoxLst(hwndParent, lpFormat, lpCaption, uType, lpArgs); } int MsgBox(HWND hwndParent, UINT uFormat, UINT uCaption, UINT uType, ...) { va_list lpArgs; INT nReturn; LPTSTR lpFormat = NULL, lpCaption = NULL; // Initialize the lpArgs parameter with va_start(). // va_start(lpArgs, uType); // Get the format and caption strings from the resource. // if ( uFormat ) lpFormat = AllocateString(NULL, uFormat); if ( uCaption ) lpCaption = AllocateString(NULL, uCaption); // Return the return value of the MessageBox() call. If there was a memory // error, 0 will be returned. // nReturn = MsgBoxLst(hwndParent, lpFormat, lpCaption, uType, lpArgs); // Free the format and caption strings. // FREE(lpFormat); FREE(lpCaption); // Return the value saved from the previous function call. // return nReturn; } void CenterDialog(HWND hwnd) { CenterDialogEx(NULL, hwnd); } void CenterDialogEx(HWND hParent, HWND hChild) { RECT rcChild, rcParent; if ( GetWindowRect(hChild, &rcChild) ) { // If parent is specified center with respect to parent. if ( hParent && (GetWindowRect(hParent, &rcParent)) ) SetWindowPos(hChild, NULL, ((rcParent.right + rcParent.left - (rcChild.right - rcChild.left)) / 2), ((rcParent.bottom + rcParent.top - (rcChild.bottom - rcChild.top)) / 2), 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); // Otherwise center with respect to screen. // else SetWindowPos(hChild, NULL, ((GetSystemMetrics(SM_CXSCREEN) - (rcChild.right - rcChild.left)) / 2), ((GetSystemMetrics(SM_CYSCREEN) - (rcChild.bottom - rcChild.top)) / 2), 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); } } INT_PTR CALLBACK SimpleDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: //CenterDialog(hwnd); return FALSE; case WM_COMMAND: EndDialog(hwnd, LOWORD(wParam)); return FALSE; default: return FALSE; } return TRUE; } INT_PTR SimpleDialogBox(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent) { return DialogBox(hInstance, lpTemplate, hWndParent, SimpleDialogProc); } /****************************************************************************\ HFONT // Returns a valid handle to a font if it is // successfully created, or NULL if something // failed. The font handle should be deleteted // with DeleteObject() when it is no longer // needed. GetFont( // This function creates a font based in the info // passed in. HWND hwndCtrl, // Handle to a control that is used for the // default font characteristics. This may be // NULL if not default is control is available. LPTSTR lpFontName, // Points to a string that contains the name of // the font to create. This parameter may be NULL // if a valid control handle is passed in. In // that case, the font of the control is used. DWORD dwFontSize, // Point size to use for the font. If it is zero, // the default is used. BOOL bSymbol // If this is TRUE, the font is set to // SYMBOL_CHARSET. Typically this is FALSE. ); \****************************************************************************/ HFONT GetFont(HWND hwndCtrl, LPTSTR lpFontName, DWORD dwFontSize, LONG lFontWeight, BOOL bSymbol) { HFONT hFont; LOGFONT lFont; BOOL bGetFont; // If the font name is passed in, then try to use that // first before getting the font of the control. // if ( lpFontName && *lpFontName ) { // Make sure the font name is not longer than // 32 characters (including the NULL terminator). // if ( lstrlen(lpFontName) >= sizeof(lFont.lfFaceName) ) return NULL; // Setup the structure to use to get the // font we want. // ZeroMemory(&lFont, sizeof(LOGFONT)); lFont.lfCharSet = DEFAULT_CHARSET; lstrcpy(lFont.lfFaceName, lpFontName); } // First try to get the font that we wanted. // if ( ( lpFontName == NULL ) || ( *lpFontName == NULLCHR ) || ( (hFont = CreateFontIndirect((LPLOGFONT) &lFont)) == NULL ) ) { // Couldn't get the font we wanted, try the font of the control // if a valid window handle was passed in. // if ( ( hwndCtrl == NULL ) || ( (hFont = (HFONT) (WORD) SendMessage(hwndCtrl, WM_GETFONT, 0, 0L)) == NULL ) ) { // All atempts to get the font failed. We must return NULL. // return NULL; } } // Return the font we have now if we don't need to // change the size or weight. // if ( (lFontWeight == 0) && (dwFontSize == 0) ) return hFont; // We must have a valid HFONT now. Fill in the structure // and setup the size and weight we wanted for it. // bGetFont = GetObject(hFont, sizeof(LOGFONT), (LPVOID) &lFont); DeleteObject(hFont); if ( bGetFont ) { // Set the bold and point size of the font. // if ( lFontWeight ) lFont.lfWeight = lFontWeight; if ( dwFontSize ) lFont.lfHeight = -MulDiv(dwFontSize, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72); if ( bSymbol ) lFont.lfCharSet = SYMBOL_CHARSET; // Create the font. // hFont = CreateFontIndirect((LPLOGFONT) &lFont); } else hFont = NULL; return hFont; } void ShowEnableWindow(HWND hwnd, BOOL bShowEnable) { EnableWindow(hwnd, bShowEnable); ShowWindow(hwnd, bShowEnable ? SW_SHOW : SW_HIDE); } /****************************************************************************\ BOOL // Returns TRUE if we are running a server OS. IsServer( // This routine checks if we're running on a // Server OS. VOID ); \****************************************************************************/ BOOL IsServer(VOID) { OSVERSIONINFOEX verInfo; BOOL fReturn = FALSE; verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if ( ( GetVersionEx((LPOSVERSIONINFO) &verInfo) ) && ( verInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) && ( ( verInfo.wProductType == VER_NT_SERVER ) || ( verInfo.wProductType == VER_NT_DOMAIN_CONTROLLER ) ) ) { fReturn = TRUE; } return fReturn; } BOOL IsIA64() /*++ =============================================================================== Routine Description: This routine checks if we're running on a 64-bit machine. Arguments: None - Return Value: TRUE - We are running on 64-bit machine. FALSE - Not a 64-bit machine. =============================================================================== --*/ { BOOL fReturn = FALSE; ULONG_PTR Wow64Info = 0; DWORD dwSt = 0; SYSTEM_INFO siSystemInfo; ZeroMemory( &siSystemInfo, sizeof(SYSTEM_INFO) ); GetSystemInfo(&siSystemInfo); if ( (siSystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) || (siSystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) ) fReturn = TRUE; if (!fReturn) { // Now make sure that GetSystemInfo isn't lying because we are in emulation mode. dwSt = NtQueryInformationProcess(GetCurrentProcess(), ProcessWow64Information, &Wow64Info, sizeof(Wow64Info), NULL); if (!NT_SUCCESS(dwSt)) { // Handle to process is bad, or the code is compiled 32-bit and running on NT4 or earlier. // Do nothing } else if (Wow64Info) { // The process is 32-bit and is running inside WOW64. // We are really on IA64 and running in 32-bit mode. fReturn = TRUE; } } return fReturn; } BOOL ValidDosName(LPCTSTR lpName) { LPCTSTR lpSearch = lpName; int nDot = 0, nSpot = 0, nLen; // Do the easy checks. // if ( ( lpSearch == NULL ) || ( *lpSearch == NULLCHR ) || ( (nLen = lstrlen(lpSearch)) > 12 ) ) { return FALSE; } // Search the string. // for (; *lpSearch; lpSearch++) { // Check for dots. // if ( *lpSearch == _T('.') ) { // Keep track of the number of dots. // nDot++; nSpot = (int) (lpSearch - lpName); } else { // Check for valid characters. // if ( !( ( ( _T('0') <= *lpSearch ) && ( *lpSearch <= _T('9') ) ) || ( ( _T('a') <= *lpSearch ) && ( *lpSearch <= _T('z') ) ) || ( ( _T('A') <= *lpSearch ) && ( *lpSearch <= _T('Z') ) ) || ( *lpSearch == _T('-') ) || ( *lpSearch == _T('_') ) || ( *lpSearch == _T('~') ) ) ) { // Invalid character. // return FALSE; } } } // Make sure the dot is in the right place. // if ( ( nDot > 1 ) || ( ( nDot == 0 ) && ( nLen > 8 ) ) || ( ( nDot == 1 ) && ( nSpot > 8 ) ) || ( ( nDot == 1 ) && ( (nLen - nSpot) > 4 ) ) ) { return FALSE; } return TRUE; } DWORD GetLineArgs(LPTSTR lpSrc, LPTSTR ** lplplpArgs, LPTSTR * lplpAllArgs) { LPTSTR lpCmdLine, lpArg, lpDst; DWORD dwArgs = 0; BOOL bQuote; // Fist make sure that we were passed in a valid pointer, we have a command // line to parse, and that we were able to allocate the memory to hold it. // if ( ( lplplpArgs != NULL ) && ( lpSrc ) && ( *lpSrc ) && ( lpCmdLine = (LPTSTR) MALLOC((lstrlen(lpSrc) + 1) * sizeof(TCHAR)) ) ) { // Fist parse the command line into NULL terminated sub strings. // lpDst = lpCmdLine; while ( *lpSrc ) { // Eat the preceeding spaces. // while ( *lpSrc == _T(' ') ) lpSrc = CharNext(lpSrc); // Make sure we still have an argument. // if ( *lpSrc == _T('\0') ) break; // Return a pointer to all the command line args if they want one. // if ( ( dwArgs == 1 ) && lplpAllArgs ) *lplpAllArgs = lpSrc; // Save the current arg pointer. // lpArg = lpDst; dwArgs++; // See if we are looking for the next quote or space. // if ( bQuote = (*lpSrc == _T('"')) ) lpSrc = CharNext(lpSrc); // Copy the argument into our allocated buffer until we // hit the separating character (which will always be a space). // while ( *lpSrc && ( bQuote || ( *lpSrc != _T(' ') ) ) ) { // We special case the quote. // if ( *lpSrc == _T('"') ) { // If the character before the quote is a backslash, then // we don't count this as the separating quote. // LPTSTR lpPrev = CharPrev(lpCmdLine, lpDst); if ( lpPrev && ( *lpPrev == _T('\\') ) ) *lpPrev = *lpSrc++; else { // Since we have found the separating quote, set this to // false so we look for the next space. // bQuote = FALSE; lpSrc++; } } else *lpDst++ = *lpSrc++; } // NULL terminate this argument. // *lpDst++ = _T('\0'); } // Now setup the pointers to each argument. Make sure we have some arguments // to return and that we have the memory allocated for the array. // if ( *lpCmdLine && dwArgs && ( *lplplpArgs = (LPTSTR *) MALLOC(dwArgs * sizeof(LPTSTR)) ) ) { DWORD dwCount = 0; // Copy a pointer to each NULL terminated sub string into our // array of arguments we are going to return. // do { *(*lplplpArgs + dwCount) = lpCmdLine; lpCmdLine += lstrlen(lpCmdLine) + 1; } while ( ++dwCount < dwArgs ); } else { // Either there were no command line arguments, or the memory allocation // failed for the list of arguments to return. // dwArgs = 0; FREE(lpCmdLine); } } return dwArgs; } DWORD GetCommandLineArgs(LPTSTR ** lplplpArgs) { return GetLineArgs(GetCommandLine(), lplplpArgs, NULL); } // // Generic singularly linked list pvItem must be allocated with MALLOC // BOOL FAddListItem(PGENERIC_LIST* ppList, PGENERIC_LIST** pppNewItem, PVOID pvItem) { if (pppNewItem && *pppNewItem == NULL) *pppNewItem = ppList; if (*pppNewItem) { if (**pppNewItem = (PGENERIC_LIST)MALLOC(sizeof(GENERIC_LIST))) { (**pppNewItem)->pNext = NULL; (**pppNewItem)->pvItem = pvItem; *pppNewItem = &((**pppNewItem)->pNext); return TRUE; } } return FALSE; } void FreeList(PGENERIC_LIST pList) { while (pList) { PGENERIC_LIST pTemp = pList; pList = pList->pNext; FREE(pTemp->pvItem); FREE(pTemp); } } // Find factory.exe from the current process, should be in same directory // BOOL FGetFactoryPath(LPTSTR pszFactoryPath) { // Attempt to locate FACTORY.EXE // // NTRAID#NTBUG9-549770-2002/02/26-acosma,georgeje - Possible buffer overflow. // if (pszFactoryPath && GetModuleFileName(NULL, pszFactoryPath, MAX_PATH)) { if (PathRemoveFileSpec(pszFactoryPath)) { PathAppend(pszFactoryPath, TEXT("FACTORY.EXE")); if (FileExists(pszFactoryPath)) return TRUE; } } return FALSE; } // Find sysprep.exe from the current process, should be in same directory // BOOL FGetSysprepPath(LPTSTR pszSysprepPath) { // Attempt to locate SYSPREP.EXE // // NTRAID#NTBUG9-549770-2002/02/26-acosma,georgeje - Possible buffer overflow. // if (pszSysprepPath && GetModuleFileName(NULL, pszSysprepPath, MAX_PATH)) { if (PathRemoveFileSpec(pszSysprepPath)) { PathAppend(pszSysprepPath, TEXT("SYSPREP.EXE")); if (FileExists(pszSysprepPath)) return TRUE; } } return FALSE; } //------------------------------------------------------------------------------------------------------ // // Function: ConnectNetworkResource // // Purpose: This function allows the user to connect to a network resource with // supplied credentials. // // Arguments: lpszPath: Network Resource that should be shared out // lpszUsername: Username for credentials, can be in form of domain\username // lpszPassword: Password to use for credentials // bState: If set to TRUE we will add the connection, if FALSE we will // attempt to delete the connection // // Returns: BOOL If the NetUse command was successful, TRUE is returned // //------------------------------------------------------------------------------------------------------ NET_API_STATUS ConnectNetworkResource(LPTSTR lpszPath, LPTSTR lpszUsername, LPTSTR lpszPassword, BOOL bState) { BOOL bRet = FALSE; USE_INFO_2 ui2; NET_API_STATUS nerr_NetUse; TCHAR szDomain[MAX_PATH] = NULLSTR, szNetUse[MAX_PATH] = NULLSTR; LPTSTR lpUser, lpSearch; // Zero out the user information structure // ZeroMemory(&ui2, sizeof(ui2)); // Copy the path into our buffer so we can work with it // lstrcpyn(szNetUse, lpszPath, AS(szNetUse)); StrRTrm(szNetUse, CHR_BACKSLASH); if ( szNetUse[0] && PathIsUNC(szNetUse) ) { // Disconnect from existing share // nerr_NetUse = NetUseDel(NULL, szNetUse, USE_NOFORCE); // We need to Add a connection // if ( bState ) { ui2.ui2_remote = szNetUse; ui2.ui2_asg_type = USE_DISKDEV; ui2.ui2_password = lpszPassword; lstrcpyn(szDomain, lpszUsername, AS(szDomain)); // Break up the Domain\Username for the NetUse function // if (lpUser = StrChr(szDomain, CHR_BACKSLASH) ) { // Put a NULL character after the domain part of the user name // and advance the pointer to point to the actual user name. // *(lpUser++) = NULLCHR; } else { // Use the computer name in the path as the domain name. // if ( lpSearch = StrChr(szNetUse + 2, CHR_BACKSLASH) ) lstrcpyn(szDomain, szNetUse + 2, (int)((lpSearch - (szNetUse + 2)) + 1)); else lstrcpyn(szDomain, szNetUse + 2, AS(szDomain)); lpUser = lpszUsername; } // Set the domain and user name pointers into our struct. // ui2.ui2_domainname = szDomain; ui2.ui2_username = lpUser; // Create a connect to the share // nerr_NetUse = NetUseAdd(NULL, 2, (LPBYTE) &ui2, NULL); } } else nerr_NetUse = NERR_UseNotFound; // Return failure/success // return nerr_NetUse; } BOOL GetUncShare(LPCTSTR lpszPath, LPTSTR lpszShare, DWORD cbShare) { BOOL bRet; LPCTSTR lpSrc = lpszPath; LPTSTR lpDst = lpszShare; DWORD dwBackslashes, dwCount; // Make sure the path is a UNC by calling the shell function. // bRet = PathIsUNC(lpszPath); // This will loop through the path string twice, each time coping all the // backslashes and then all the non-backslashes. So if the string passed // in was "\\COMPUTER\SHARE\DIR\FILE.NAME", the first pass will copy // "\\COMPUTER" and the next pass would then copy "\SHARE" so the final // string would then be "\\COMPUTER\SHARE". This loop also verifies there // are the correct number of backslashes and non-backslashes. If there is // no return buffer, then we just are verifing the share. // for ( dwBackslashes = 2; dwBackslashes && bRet; dwBackslashes-- ) { // First copy the backslashes. // dwCount = 0; while ( _T('\\') == *lpSrc ) { if ( lpDst && cbShare ) { *lpDst++ = *lpSrc; cbShare--; } lpSrc++; dwCount++; } // Make sure the number of backslashes is correct. // The fist pass there should be two and the next // pass should be just one. // if ( dwBackslashes != dwCount ) { bRet = FALSE; } else { // Now copy the non-backslashes. // dwCount = 0; while ( ( *lpSrc ) && ( _T('\\') != *lpSrc ) ) { if ( lpDst && cbShare ) { *lpDst++ = *lpSrc; cbShare--; } lpSrc++; dwCount++; } // Make sure there was at least one non-backslash. // character. // // Also if we are on the first pass and the path // buffer is already empty, then we don't have the // share part so just error out. // if ( ( 0 == dwCount ) || ( ( 2 == dwBackslashes ) && ( NULLCHR == *lpSrc ) ) ) { bRet = FALSE; } } } // Only fix up the return buffer if there is one. // if ( lpszShare ) { // Make sure that we didn't fail and that we still // have room for the null terminator. // if ( bRet && cbShare ) { // Don't forget to null terminate the return string. // *lpDst = NULLCHR; } else { // If we failed or ran out of buffer room, make sure // we don't return anything. // *lpszShare = NULLCHR; } } return bRet; } DWORD GetSkuType() { DWORD dwRet = 0; OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if ( GetVersionEx((LPOSVERSIONINFO) &osvi) ) { if ( VER_NT_WORKSTATION == osvi.wProductType ) { if ( GET_FLAG(osvi.wSuiteMask, VER_SUITE_PERSONAL) ) { dwRet = VER_SUITE_PERSONAL; } else { dwRet = VER_NT_WORKSTATION; } } else { if ( GET_FLAG(osvi.wSuiteMask, VER_SUITE_DATACENTER) ) { dwRet = VER_SUITE_DATACENTER; } else if ( GET_FLAG(osvi.wSuiteMask, VER_SUITE_ENTERPRISE) ) { dwRet = VER_SUITE_ENTERPRISE; } else if ( GET_FLAG(osvi.wSuiteMask, VER_SUITE_BLADE) ) { dwRet = VER_SUITE_BLADE; } else { dwRet = VER_NT_SERVER; } } } return dwRet; }