//--------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation 1991-1993 // // File: util.c // // History: // 01-13-93 SatoNa Added this comment block, added WEP. // 05-03-93 SatoNa Shared memory support. // //--------------------------------------------------------------------------- #include "shellprv.h" #pragma hdrstop #ifdef DEBUG extern UINT wDebugMask; #endif // sane way to get the msg pos into a point, mostly needed for win32 void GetMsgPos(POINT *ppt) { DWORD dw = GetMessagePos(); ppt->x = LOWORD(dw); ppt->y = HIWORD(dw); } /* This gets the number of consecutive chrs of the same kind. This is used * to parse the time picture. Returns 0 on error. */ int GetPict(TCHAR ch, LPTSTR szStr) { int count; count = 0; while (ch == *szStr++) count++; return(count); } /* This picks up the values in wValArray, converts them * in a string containing the formatted date. * wValArray should contain Month-Day-Year (in that order). */ int CreateDate(WORD *wValArray, LPTSTR szOutStr) { int i; int cchPictPart; WORD wDigit; WORD wIndex; WORD wTempVal; LPTSTR pszPict, pszInStr; TCHAR szShortDate[20]; GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, szShortDate, ARRAYSIZE(szShortDate)); pszPict = szShortDate; pszInStr = szOutStr; for (i=0; (i < 3) && (*pszPict); i++) { cchPictPart = GetPict(*pszPict, pszPict); switch (*pszPict) { case TEXT('M'): case TEXT('m'): { wIndex = 0; break; } case TEXT('D'): case TEXT('d'): { wIndex = 1; break; } case TEXT('Y'): case TEXT('y'): { wIndex = 2; if (cchPictPart == 4) { if (wValArray[2] >=100) { *pszInStr++ = TEXT('2'); *pszInStr++ = TEXT('0'); wValArray[2]-= 100; } else { *pszInStr++ = TEXT('1'); *pszInStr++ = TEXT('9'); } } break; } default: { goto CDFillIn; break; } } /* This assumes that the values are of two digits only. */ wTempVal = wValArray[wIndex]; wDigit = wTempVal / 10; if (wDigit) *pszInStr++ = (TCHAR)(wDigit + TEXT('0')); else if (cchPictPart > 1) *pszInStr++ = TEXT('0'); *pszInStr++ = (TCHAR)((wTempVal % 10) + TEXT('0')); pszPict += cchPictPart; CDFillIn: /* Add the separator. */ while ((*pszPict) && (*pszPict != TEXT('M')) && (*pszPict != TEXT('m')) && (*pszPict != TEXT('D')) && (*pszPict != TEXT('d')) && (*pszPict != TEXT('Y')) && (*pszPict != TEXT('y'))) { *pszInStr++ = *pszPict++; } } *pszInStr = TEXT('\0'); return lstrlen(szOutStr); } #define DATEMASK 0x001F #define MONTHMASK 0x01E0 #define MINUTEMASK 0x07E0 #define SECONDSMASK 0x001F #define DATESEPERATOR TEXT('-') #define TIMESEPERATOR TEXT(':') int WINAPI GetDateString(WORD wDate, LPTSTR szStr) { WORD wValArray[3]; wValArray[0] = (wDate & MONTHMASK) >> 5; /* Month */ wValArray[1] = (wDate & DATEMASK); /* Date */ wValArray[2] = (wDate >> 9) + 80; /* Year */ return CreateDate(wValArray, szStr); } WORD WINAPI ParseDateString(LPTSTR pszStr, BOOL *pfValid) { // // We need to loop through the string and extract off the month/day/year // We will do it in the order of the NlS definition... // WORD wParts[3]; int i; int cchPictPart; WORD wIndex; WORD wTempVal; TCHAR szShortDate[20]; LPTSTR pszPict; GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, szShortDate, ARRAYSIZE(szShortDate)); pszPict = szShortDate; while (*pszPict && (*pszPict == *pszStr)) { pszPict++; pszStr++; } for (i=0; i < 3; i++) { cchPictPart = GetPict(*pszPict, pszPict); switch (*pszPict) { case TEXT('M'): case TEXT('m'): wIndex = 0; break; case TEXT('D'): case TEXT('d'): wIndex = 1; break; case TEXT('Y'): case TEXT('y'): wIndex = 2; break; default: if (pfValid) { *pfValid = FALSE; return(0); } } // We now want to loop through each of the characters while // they are numbers and build the number; // wTempVal = 0; while ((*pszStr >= TEXT('0')) && (*pszStr <= TEXT('9'))) { wTempVal = wTempVal * 10 + (WORD)(*pszStr - TEXT('0')); pszStr++; } wParts[wIndex] = wTempVal; // Now make sure we have the correct separator pszPict += cchPictPart; if (*pszPict != *pszStr) { if (pfValid) { *pfValid = FALSE; return(0); } } while (*pszPict && (*pszPict == *pszStr)) { // // The separator can actually be more than one character // in length. // pszPict++; // align to the next field pszStr++; // Align to next field } } // // Do some simple checks to see if the date looks half way reasonable. // if (wParts[2] < 80) wParts[2] += (2000 - 1900); // Wrap to next century but leave as two digits... if (wParts[2] >= 1900) wParts[2] -= 1900; // Get rid of Century if ((wParts[0] == 0) || (wParts[0] > 12) || (wParts[1] == 0) || (wParts[1] > 31) || (wParts[2] >= 200)) { *pfValid = FALSE; return(0); } // We now have the three parts so lets construct the date value if (pfValid) *pfValid = TRUE; // Now construct the date number return ((wParts[2] - 80) << 9) + (wParts[0] << 5) + wParts[1]; } BOOL IsNullTime(const FILETIME *pft) { FILETIME ftNull = {0, 0}; return CompareFileTime(&ftNull, pft) == 0; } void Int64ToStr( _int64 n, LPTSTR lpBuffer) { TCHAR szTemp[MAX_INT64_SIZE]; _int64 iChr; iChr = 0; do { szTemp[iChr++] = TEXT('0') + (n % 10); n = n / 10; } while (n != 0); do { iChr--; *lpBuffer++ = szTemp[iChr]; } while (iChr != 0); *lpBuffer++ = '\0'; } // takes a DWORD add commas etc to it and puts the result in the buffer LPTSTR WINAPI AddCommas64(_int64 n, LPTSTR pszResult) { // BUGBUGBC: 40 is bogus, it requires callers to know their buffer must // be 40 TCHAR szTemp[MAX_COMMA_NUMBER_SIZE]; TCHAR szSep[5]; NUMBERFMT nfmt; nfmt.NumDigits=0; nfmt.LeadingZero=0; GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep)); nfmt.Grouping = StrToInt(szSep); GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep)); nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep; nfmt.NegativeOrder= 0; Int64ToStr(n, szTemp); // BUGBUG:: Should have passed in size.. if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, MAX_COMMA_NUMBER_SIZE) == 0) lstrcpy(pszResult, szTemp); return pszResult; } // takes a DWORD add commas etc to it and puts the result in the buffer LPTSTR WINAPI AddCommas(DWORD dw, LPTSTR pszResult) { return AddCommas64( dw, pszResult ); } #ifndef BUGBUG_BOBDAY #ifndef UNICODE // // This is just temporary until the entire shell32.dll is unicode // // takes a DWORD add commas etc to it and puts the result in the buffer LPWSTR WINAPI AddCommasW(DWORD dw, LPWSTR pszResult) { WCHAR szTemp[MAX_COMMA_NUMBER_SIZE]; WCHAR szSep[5]; NUMBERFMTW nfmt; nfmt.NumDigits=0; nfmt.LeadingZero=0; GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep)); nfmt.Grouping = StrToIntW(szSep); GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep)); nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep; nfmt.NegativeOrder= 0; wsprintfW(szTemp, L"%lu", dw); // BUGBUG:: Should have passed in size.. if (GetNumberFormatW(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, MAX_COMMA_NUMBER_SIZE) == 0) lstrcpyW(pszResult, szTemp); return pszResult; } #endif #endif // // Add Peta 10^15 and Exa 10^18 to support 64-bit integers. // const short pwOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB, IDS_ORDERGB, IDS_ORDERTB, IDS_ORDERPB, IDS_ORDEREB}; /* converts numbers into sort formats * 532 -> 523 bytes * 1340 -> 1.3KB * 23506 -> 23.5KB * -> 2.4MB * -> 5.2GB */ LPTSTR WINAPI ShortSizeFormat64(__int64 dw64, LPTSTR szBuf) { int i; _int64 wInt; UINT wLen, wDec; TCHAR szTemp[MAX_COMMA_NUMBER_SIZE], szOrder[20], szFormat[5]; if (dw64 < 1000) { wsprintf(szTemp, TEXT("%d"), LODWORD(dw64)); i = 0; goto AddOrder; } for (i = 1; i= 1000L * 1024L; dw64 >>= 10, i++); /* do nothing */ wInt = dw64 >> 10; AddCommas64(wInt, szTemp); wLen = lstrlen(szTemp); if (wLen < 3) { wDec = LODWORD(dw64 - wInt * 1024L) * 1000 / 1024; // At this point, wDec should be between 0 and 1000 // we want get the top one (or two) digits. wDec /= 10; if (wLen == 2) wDec /= 10; // Note that we need to set the format before getting the // intl char. lstrcpy(szFormat, TEXT("%02d")); szFormat[2] = TEXT('0') + 3 - wLen; GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szTemp+wLen, ARRAYSIZE(szTemp)-wLen); wLen = lstrlen(szTemp); wLen += wsprintf(szTemp+wLen, szFormat, wDec); } AddOrder: LoadString(HINST_THISDLL, pwOrders[i], szOrder, ARRAYSIZE(szOrder)); wsprintf(szBuf, szOrder, (LPTSTR)szTemp); return szBuf; } LPTSTR WINAPI ShortSizeFormat(DWORD dw, LPTSTR szBuf) { return(ShortSizeFormat64((__int64)dw, szBuf)); } LPTSTR SizeFormatAsK64(_int64 n, LPTSTR szBuf) { static TCHAR szOrder[10] = TEXT(""); TCHAR szNum[MAX_COMMA_AS_K_SIZE]; if (szOrder[0] == TEXT('\0')) LoadString(HINST_THISDLL, IDS_ORDERKB, szOrder, ARRAYSIZE(szOrder)); AddCommas64((n + 1023) / 1024, szNum); wsprintf(szBuf, szOrder, szNum); return szBuf; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: Int64ToString // // DESCRIPTION: // Converts the numeric value of a _int64 to a text string. // The string may optionally be formatted to include decimal places // and commas according to current user locale settings. // // ARGUMENTS: // n // The 64-bit integer to format. // // szOutStr // Address of the destination buffer. // // nSize // Number of characters in the destination buffer. // // bFormat // TRUE = Format per locale settings. // FALSE = Leave number unformatted. // // pFmt // Address of a number format structure of type NUMBERFMT. // If NULL, the function automatically provides this information // based on the user's default locale settings. // // dwNumFmtFlags // Encoded flag word indicating which members of *pFmt to use in // formatting the number. If a bit is clear, the user's default // locale setting is used for the corresponding format value. These // constants can be OR'd together. // // NUMFMT_IDIGITS // NUMFMT_ILZERO // NUMFMT_SGROUPING // NUMFMT_SDECIMAL // NUMFMT_STHOUSAND // NUMFMT_INEGNUMBER // /////////////////////////////////////////////////////////////////////////////// INT WINAPI Int64ToString(_int64 n, LPTSTR szOutStr, UINT nSize, BOOL bFormat, NUMBERFMT *pFmt, DWORD dwNumFmtFlags) { INT nResultSize; TCHAR szBuffer[_MAX_PATH + 1]; NUMBERFMT NumFmt; TCHAR szDecimalSep[5]; TCHAR szThousandSep[5]; Assert(NULL != szOutStr); // // Use only those fields in caller-provided NUMBERFMT structure // that correspond to bits set in dwNumFmtFlags. If a bit is clear, // get format value from locale info. // if (bFormat) { TCHAR szInfo[20]; if (NULL == pFmt) dwNumFmtFlags = 0; // Get all format data from locale info. if (dwNumFmtFlags & NUMFMT_IDIGITS) { NumFmt.NumDigits = pFmt->NumDigits; } else { GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, szInfo, ARRAYSIZE(szInfo)); NumFmt.NumDigits = StrToLong(szInfo); } if (dwNumFmtFlags & NUMFMT_ILZERO) { NumFmt.LeadingZero = pFmt->LeadingZero; } else { GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILZERO, szInfo, ARRAYSIZE(szInfo)); NumFmt.LeadingZero = StrToLong(szInfo); } if (dwNumFmtFlags & NUMFMT_SGROUPING) { NumFmt.Grouping = pFmt->Grouping; } else { GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szInfo, ARRAYSIZE(szInfo)); NumFmt.Grouping = StrToLong(szInfo); } if (dwNumFmtFlags & NUMFMT_SDECIMAL) { NumFmt.lpDecimalSep = pFmt->lpDecimalSep; } else { GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSep, ARRAYSIZE(szDecimalSep)); NumFmt.lpDecimalSep = szDecimalSep; } if (dwNumFmtFlags & NUMFMT_STHOUSAND) { NumFmt.lpThousandSep = pFmt->lpThousandSep; } else { GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szThousandSep, ARRAYSIZE(szThousandSep)); NumFmt.lpThousandSep = szThousandSep; } if (dwNumFmtFlags & NUMFMT_INEGNUMBER) { NumFmt.NegativeOrder = pFmt->NegativeOrder; } else { GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER, szInfo, ARRAYSIZE(szInfo)); NumFmt.NegativeOrder = StrToLong(szInfo); } pFmt = &NumFmt; } Int64ToStr( n, szBuffer); // // Format the number string for the locale if the caller wants a // formatted number string. // if (bFormat) { if ( 0 != ( nResultSize = GetNumberFormat( LOCALE_USER_DEFAULT, // User's locale 0, // No flags szBuffer, // Unformatted number string pFmt, // Number format info szOutStr, // Output buffer nSize )) ) // Chars in output buffer. { // // Remove nul terminator char from return size count. // --nResultSize; } } else { // // GetNumberFormat call failed, so just return the number string // unformatted. // lstrcpyn(szOutStr, szBuffer, nSize); nResultSize = lstrlen(szOutStr); } return nResultSize; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: LargeIntegerToString // // DESCRIPTION: // Converts the numeric value of a LARGE_INTEGER to a text string. // The string may optionally be formatted to include decimal places // and commas according to current user locale settings. // // ARGUMENTS: // pN // Address of the large integer to format. // // See description of Int64ToString for remaining arguments. // /////////////////////////////////////////////////////////////////////////////// INT WINAPI LargeIntegerToString(LARGE_INTEGER *pN, LPTSTR szOutStr, UINT nSize, BOOL bFormat, NUMBERFMT *pFmt, DWORD dwNumFmtFlags) { Assert(NULL != pN); return Int64ToString(pN->QuadPart, szOutStr, nSize, bFormat, pFmt, dwNumFmtFlags); } #define ISSEP(c) ((c) == TEXT('=') || (c) == TEXT(',')) #define ISWHITE(c) ((c) == TEXT(' ') || (c) == TEXT('\t') || (c) == TEXT('\n') || (c) == TEXT('\r')) #define ISNOISE(c) ((c) == TEXT('"')) #define EOF 26 #define QUOTE TEXT('"') #define COMMA TEXT(',') #define SPACE TEXT(' ') #define EQUAL TEXT('=') /* BOOL ParseField(szData,n,szBuf,iBufLen) * * Given a line from SETUP.INF, will extract the nth field from the string * fields are assumed separated by comma's. Leading and trailing spaces * are removed. * * ENTRY: * * szData : pointer to line from SETUP.INF * n : field to extract. ( 1 based ) * 0 is field before a '=' sign * szDataStr : pointer to buffer to hold extracted field * iBufLen : size of buffer to receive extracted field. * * EXIT: returns TRUE if successful, FALSE if failure. * */ BOOL WINAPI ParseField(LPCTSTR szData, int n, LPTSTR szBuf, int iBufLen) { BOOL fQuote = FALSE; LPCTSTR pszInf = szData; LPTSTR ptr; int iLen = 1; if (!szData || !szBuf) return FALSE; /* * find the first separator */ while (*pszInf && !ISSEP(*pszInf)) { if (*pszInf == QUOTE) fQuote = !fQuote; pszInf = CharNext(pszInf); } if (n == 0 && *pszInf != TEXT('=')) return FALSE; if (n > 0 && *pszInf == TEXT('=') && !fQuote) // Change szData to point to first field szData = ++pszInf; // Ok for DBCS /* * locate the nth comma, that is not inside of quotes */ fQuote = FALSE; while (n > 1) { while (*szData) { if (!fQuote && ISSEP(*szData)) break; if (*szData == QUOTE) fQuote = !fQuote; szData = CharNext(szData); } if (!*szData) { szBuf[0] = 0; // make szBuf empty return FALSE; } szData = CharNext(szData); // we could do ++ here since we got here // after finding comma or equal n--; } /* * now copy the field to szBuf */ while (ISWHITE(*szData)) szData = CharNext(szData); // we could do ++ here since white space can // NOT be a lead byte fQuote = FALSE; ptr = szBuf; // fill output buffer with this while (*szData) { if (*szData == QUOTE) { // // If we're in quotes already, maybe this // is a double quote as in: "He said ""Hello"" to me" // if (fQuote && *(szData+1) == QUOTE) // Yep, double-quoting - QUOTE is non-DBCS { if (iLen < iBufLen) { *ptr++ = QUOTE; ++iLen; } szData++; // now skip past 1st quote } else fQuote = !fQuote; } else if (!fQuote && ISSEP(*szData)) break; else { if ( iLen < iBufLen ) { *ptr++ = *szData; // Thank you, Dave ++iLen; } if ( IsDBCSLeadByte(*szData) && (iLen < iBufLen) ) { *ptr++ = szData[1]; ++iLen; } } szData = CharNext(szData); } /* * remove trailing spaces */ while (ptr > szBuf) { ptr = CharPrev(szBuf, ptr); if (!ISWHITE(*ptr)) { ptr = CharNext(ptr); break; } } *ptr = 0; return TRUE; } // Sets and clears the "wait" cursor. // REVIEW UNDONE - wait a specific period of time before actually bothering // to change the cursor. // REVIEW UNDONE - support for SetWaitPercent(); // BOOL bSet TRUE if you want to change to the wait cursor, FALSE if // you want to change it back. void WINAPI SetAppStartingCursor(HWND hwnd, BOOL bSet) { #ifdef WINNT DWORD dwTargetProcID; #endif //g_hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); if (hwnd && IsWindow(hwnd)) { HWND hwndOwner; while((NULL != (hwndOwner = GetParent(hwnd))) || (NULL != (hwndOwner = GetWindow(hwnd, GW_OWNER)))) { hwnd = hwndOwner; } #ifdef WINNT // SendNotify is documented to only work in-process (and can // crash if we pass the pnmhdr across process boundaries on // NT, because DLLs aren't all shared in one address space). // So, if this SendNotify would go cross-process, blow it off. GetWindowThreadProcessId(hwnd, &dwTargetProcID); if (GetCurrentProcessId() == dwTargetProcID) #endif SendNotify(hwnd, NULL, bSet ? NM_STARTWAIT : NM_ENDWAIT, NULL); } } HWND WINAPI GetTopLevelAncestor(HWND hWnd) { HWND hwndTemp; while ((hwndTemp=GetParent(hWnd)) != NULL) { hWnd = hwndTemp; } return(hWnd); } BOOL _SHIsMenuSeparator(HMENU hm, int i) { MENUITEMINFO mii; mii.cbSize = SIZEOF(MENUITEMINFO); mii.fMask = MIIM_TYPE; mii.cch = 0; // WARNING: We MUST initialize it to 0!!! if (!GetMenuItemInfo(hm, i, TRUE, &mii)) { return(FALSE); } if (mii.fType & MFT_SEPARATOR) { return(TRUE); } return(FALSE); } // Copy a menu onto the beginning or end of another menu // Adds uIDAdjust to each menu ID (pass in 0 for no adjustment) // Will not add any item whose adjusted ID is greater than uMaxIDAdjust // (pass in 0xffff to allow everything) // Returns one more than the maximum adjusted ID that is used // UINT WINAPI Shell_MergeMenus(HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags) { int nItem; HMENU hmSubMenu; BOOL bAlreadySeparated; MENUITEMINFO miiSrc; TCHAR szName[256]; UINT uTemp, uIDMax = uIDAdjust; if (!hmDst || !hmSrc) { goto MM_Exit; } nItem = GetMenuItemCount(hmDst); if (uInsert >= (UINT)nItem) { uInsert = (UINT)nItem; bAlreadySeparated = TRUE; } else { bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);; } if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) { // Add a separator between the menus InsertMenu(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); bAlreadySeparated = TRUE; } // Go through the menu items and clone them for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--) { miiSrc.cbSize = SIZEOF(MENUITEMINFO); miiSrc.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA; // We need to reset this every time through the loop in case // menus DON'T have IDs miiSrc.fType = (UINT)MFT_STRING; miiSrc.dwTypeData = szName; miiSrc.dwItemData = 0; miiSrc.cch = ARRAYSIZE(szName); if (!GetMenuItemInfo(hmSrc, nItem, TRUE, &miiSrc)) { continue; } if (miiSrc.fType & MFT_SEPARATOR) { // This is a separator; don't put two of them in a row if (bAlreadySeparated) { continue; } bAlreadySeparated = TRUE; } else if (miiSrc.hSubMenu) { if (uFlags & MM_SUBMENUSHAVEIDS) { // Adjust the ID and check it miiSrc.wID += uIDAdjust; if (miiSrc.wID > uIDAdjustMax) { continue; } if (uIDMax <= miiSrc.wID) { uIDMax = miiSrc.wID + 1; } } else { // Don't set IDs for submenus that didn't have // them already miiSrc.fMask &= ~MIIM_ID; } hmSubMenu = miiSrc.hSubMenu; miiSrc.hSubMenu = CreatePopupMenu(); if (!miiSrc.hSubMenu) { goto MM_Exit; } uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags&MM_SUBMENUSHAVEIDS); if (uIDMax <= uTemp) { uIDMax = uTemp; } bAlreadySeparated = FALSE; } else { // Adjust the ID and check it miiSrc.wID += uIDAdjust; if (miiSrc.wID > uIDAdjustMax) { continue; } if (uIDMax <= miiSrc.wID) { uIDMax = miiSrc.wID + 1; } bAlreadySeparated = FALSE; } if (!InsertMenuItem(hmDst, uInsert, TRUE, &miiSrc)) { goto MM_Exit; } } // Ensure the correct number of separators at the beginning of the // inserted menu items if (uInsert == 0) { if (bAlreadySeparated) { DeleteMenu(hmDst, uInsert, MF_BYPOSITION); } } else { if (_SHIsMenuSeparator(hmDst, uInsert-1)) { if (bAlreadySeparated) { DeleteMenu(hmDst, uInsert, MF_BYPOSITION); } } else { if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) { // Add a separator between the menus InsertMenu(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); } } } MM_Exit: return(uIDMax); } void WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet) { // // No need to put this one in per-instance data section. // static struct { UINT cbSize; SHELLSTATE ss; } ShellState = { 0, } ; if (ShellState.cbSize != SIZEOF(ShellState)) { ENTERCRITICAL; if (ShellState.cbSize != SIZEOF(ShellState)) { DWORD dwType; DWORD dwSize = SIZEOF(ShellState); HKEY hkey = SHGetExplorerHkey(HKEY_CURRENT_USER, FALSE); if (!hkey || RegQueryValueEx(hkey, (LPTSTR)c_szShellState, NULL, &dwType, (LPBYTE)&ShellState, &dwSize)!=ERROR_SUCCESS || ShellState.cbSize!=SIZEOF(ShellState)) { // 0 should be the default for everything _fmemset(&ShellState.ss, 0, SIZEOF(ShellState.ss)); ShellState.cbSize = SIZEOF(ShellState); } } LEAVECRITICAL; } if (bSet) { BOOL fSave = FALSE; if ((dwMask & SSF_SHOWALLOBJECTS) && (ShellState.ss.fShowAllObjects != lpss->fShowAllObjects)) { ShellState.ss.fShowAllObjects = lpss->fShowAllObjects; fSave = TRUE; } if ((dwMask & SSF_SHOWEXTENSIONS) && (ShellState.ss.fShowExtensions != lpss->fShowExtensions)) { ShellState.ss.fShowExtensions = lpss->fShowExtensions; fSave = TRUE; } if ((dwMask & SSF_SHOWCOMPCOLOR) && (ShellState.ss.fShowCompColor != lpss->fShowCompColor)) { ShellState.ss.fShowCompColor = lpss->fShowCompColor; fSave = TRUE; } if ((dwMask & SSF_NOCONFIRMRECYCLE) && (ShellState.ss.fNoConfirmRecycle != lpss->fNoConfirmRecycle)) { ShellState.ss.fNoConfirmRecycle = lpss->fNoConfirmRecycle; fSave = TRUE; } if (dwMask & SSF_HIDDENFILEEXTS) { // Setting hidden extensions is not supported } if (fSave) { // We save 8 extra bytes for the ExcludeFileExts stuff. // Oh well. HKEY hkey = SHGetExplorerHkey(HKEY_CURRENT_USER, TRUE); if (hkey) { RegSetValueEx(hkey, c_szShellState, 0L, REG_BINARY, (LPBYTE)&ShellState, SIZEOF(ShellState)); } } } else { if (dwMask & SSF_SHOWALLOBJECTS) { lpss->fShowAllObjects = ShellState.ss.fShowAllObjects; } if (dwMask & SSF_SHOWEXTENSIONS) { lpss->fShowExtensions = ShellState.ss.fShowExtensions; } if (dwMask & SSF_SHOWCOMPCOLOR) { lpss->fShowCompColor = ShellState.ss.fShowCompColor; } if (dwMask & SSF_NOCONFIRMRECYCLE) { lpss->fNoConfirmRecycle = ShellState.ss.fNoConfirmRecycle; } if (dwMask & SSF_HIDDENFILEEXTS) { // BUGBUG: If changes were made to the Registry, this may // not be completely accurate _SHGetExcludeFileExts(lpss->pszHiddenFileExts, lpss->cbHiddenFileExts/SIZEOF(TCHAR)); } } } //=========================================================================== // DKA stuff (moved from filemenu.c) //=========================================================================== typedef struct _DKAITEM { // dkai TCHAR _szKey[CCH_KEYMAX]; } DKAITEM, *PDKAITEM; typedef const DKAITEM * PCDKAITEM; typedef struct _DKA { // dka HDSA _hdsa; HKEY _hkey; } DKA, *PDKA; // // This function creates a dynamic registration key array from the // specified location of the registration base. // // Arguments: // hkey -- Identifies a currently open key (which can be HKEY_CLASSES_ROOT). // pszSubKey -- Points to a null-terminated string specifying the name of the // subkey from which we enumerate the list of subkeys. // fDefault -- If true, it will only load the keys that are enumarted in // pszSubKey's value // // Returns: // The return value is non-zero handle to the created dynamic key array // if the function is successful. Otherwise, NULL. // // History: // 05-06-93 SatoNa Created // // Notes: // The dynamic key array should be destroyed by calling DKA_Destroy function. // HDKA DKA_Create(HKEY hkey, LPCTSTR pszSubKey, LPCTSTR pszFirst, LPCTSTR pszDefOrder, BOOL fDefault) { PDKA pdka = (PDKA)LocalAlloc(LPTR, SIZEOF(DKA)); DKAITEM dkai; if (pdka) { pdka->_hdsa=DSA_Create(SIZEOF(DKAITEM),4); if (pdka->_hdsa) { if (RegOpenKeyEx(hkey, pszSubKey, 0L, MAXIMUM_ALLOWED, &pdka->_hkey)!=ERROR_SUCCESS) { DSA_Destroy(pdka->_hdsa); pdka->_hdsa=NULL; } } // Check if the creation succceeded if (pdka->_hdsa) { // Yes, add keys TCHAR szValue[MAXPATHLEN*2+CCH_KEYMAX]; LONG cchValue=ARRAYSIZE(szValue)-CCH_KEYMAX; LONG cbValue; LPTSTR lpszValue = szValue; TCHAR szKey[CCH_KEYMAX]; int i; LPTSTR psz; HKEY hkeyCmd; *szValue = TEXT('\0'); // if there's something we need to add first, do it now. if (pszFirst) { lstrcpy(szValue, pszFirst); lstrcat(szValue, c_szSpace); i = lstrlen(szValue); cchValue -= i; lpszValue += i; } // First, add the subkeys from the value of the specified key // This should never fail, since we just opened this key cbValue = cchValue * SIZEOF(TCHAR); RegQueryValue(pdka->_hkey, NULL, lpszValue, &cbValue); if (!*szValue && pszDefOrder) { // If there is no value, default to open for 3.1 compatibility lstrcpy(szValue, pszDefOrder); } psz = szValue; do { // skip the space or comma characters while(*psz==TEXT(' ') || *psz==TEXT(',')) psz++; // NLS Notes: OK to ++ if (*psz) { // Search for the space or comma character LPTSTR pszNext= psz + StrCSpn(psz, TEXT(" ,")); if (*pszNext) { *pszNext++=TEXT('\0'); // NLS Notes: OK to ++ } // Verify that the key exists before adding it to the list if (RegOpenKeyEx(pdka->_hkey, psz, 0L, MAXIMUM_ALLOWED, &hkeyCmd) == ERROR_SUCCESS) { lstrcpy(dkai._szKey, psz); DSA_InsertItem(pdka->_hdsa, INT_MAX, &dkai); RegCloseKey(hkeyCmd); } psz=pszNext; } } while(psz && *psz); if (!fDefault) { // Then, append the rest if they are not in the list yet. for (i=0; RegEnumKey(pdka->_hkey, i, szKey, ARRAYSIZE(szKey))==ERROR_SUCCESS; i++) { int idsa; // // Check if the key is already in the list. // for (idsa=0; idsa_hdsa) ; idsa++) { PDKAITEM pdkai = (PDKAITEM)DSA_GetItemPtr(pdka->_hdsa, idsa); if (lstrcmpi(szKey, pdkai->_szKey)==0) break; } if (idsa==DSA_GetItemCount(pdka->_hdsa)) { // // No, append it. // lstrcpy(dkai._szKey, szKey); DSA_InsertItem(pdka->_hdsa, INT_MAX, &dkai); } } } } else { // No, free the memory and return NULL. LocalFree((HLOCAL)pdka); pdka=NULL; } } return (HDKA)pdka; } int DKA_GetItemCount(HDKA pdka) { return DSA_GetItemCount(pdka->_hdsa); } LPCTSTR DKA_GetKey(HDKA pdka, int iItem) { PDKAITEM pdkai = (PDKAITEM)DSA_GetItemPtr(pdka->_hdsa, iItem); return pdkai->_szKey; } // // This function returns the value of specified sub-key. // // Arguments: // hdka -- Specifies the dynamic key array // iItem -- Specifies the index to the sub-key // pszValue -- Points to a buffefr that contains the text string when // the function returns. // pcb -- Points to a variable specifying the sixze, in bytes, of the buffer // pointer by the pszValue parameter. When the function returns, // this variable contains the size of the string copied to pszVlaue, // including the null-terminating character. // // History: // 05-06-93 SatoNa Created // LONG DKA_QueryValue(HDKA pdka, int iItem, LPTSTR pszValue, LONG * pcb) { PCDKAITEM pdkai = DSA_GetItemPtr(pdka->_hdsa, iItem); if (pdkai) { return RegQueryValue(pdka->_hkey, pdkai->_szKey, pszValue, pcb); } return ERROR_INVALID_PARAMETER; } // // This function destroys the dynamic key array. // Arguments: // hdka -- Specifies the dynamic key array // // History: // 05-06-93 SatoNa Created // void DKA_Destroy(HDKA pdka) { if (pdka) { RegCloseKey(pdka->_hkey); DSA_Destroy(pdka->_hdsa); LocalFree((HLOCAL)pdka); } } HDCA DCA_Create() { HDSA hdsa = DSA_Create(SIZEOF(CLSID),4); return (HDCA)hdsa; } void DCA_Destroy(HDCA hdca) { DSA_Destroy((HDSA)hdca); } int DCA_GetItemCount(HDCA hdca) { return DSA_GetItemCount((HDSA)hdca); } const CLSID * DCA_GetItem(HDCA hdca, int i) { return (const CLSID *)DSA_GetItemPtr((HDSA)hdca, i); } BOOL DCA_AddItem(HDCA hdca, REFCLSID rclsid) { int ccls = DCA_GetItemCount(hdca); int icls; for ( icls=0; iclslpVtbl->Read(pstm, &cch, SIZEOF(cch), NULL); // size of data if (SUCCEEDED(hres)) { if (cch >= (USHORT)cchBuf) { DebugMsg(DM_TRACE, TEXT("truncating string read(%d to %d)"), cchBuf, cch); cch = (USHORT)cchBuf - 1; // leave room for null terminator } hres = pstm->lpVtbl->Read(pstm, psz, cch * SIZEOF(TCHAR), NULL); if (SUCCEEDED(hres)) psz[cch] = 0; // add NULL terminator } return hres; } HRESULT Stream_WriteString(LPSTREAM pstm, LPCTSTR psz) { SHORT cch = lstrlen(psz); HRESULT hres = pstm->lpVtbl->Write(pstm, &cch, SIZEOF(cch), NULL); if (SUCCEEDED(hres)) hres = pstm->lpVtbl->Write(pstm, psz, cch * SIZEOF(TCHAR), NULL); return hres; } //---------------------------------------------------------------------------- typedef struct { UINT uFlag; INT nValue; LPCTSTR pszKey; LPCTSTR pszValue; } RESTRICTIONITEMS; TCHAR const c_szNoRun[] = TEXT("NoRun"); TCHAR const c_szNoClose[] = TEXT("NoClose"); TCHAR const c_szNoSaveSettings[] = TEXT("NoSaveSettings"); TCHAR const c_szNoFileMenu[] = TEXT("NoFileMenu"); TCHAR const c_szNoSetFolders[] = TEXT("NoSetFolders"); TCHAR const c_szNoSetTaskbar[] = TEXT("NoSetTaskbar"); TCHAR const c_szNoDesktop[] = TEXT("NoDesktop"); TCHAR const c_szNoFind[] = TEXT("NoFind"); TCHAR const c_szNoDrives[] = TEXT("NoDrives"); TCHAR const c_szNoDriveAutoRun[] = TEXT("NoDriveAutoRun"); TCHAR const c_szNoDriveTypeAutoRun[] = TEXT("NoDriveTypeAutoRun"); TCHAR const c_szNoNetHood[] = TEXT("NoNetHood"); TCHAR const c_szNoStartBanner[] = TEXT("NoStartBanner"); TCHAR const c_szNoStartMenuSubFolders[] = TEXT("NoStartMenuSubFolders"); TCHAR const c_szMyDocsOnNet[] = TEXT("MyDocsOnNet"); TCHAR const c_szNoExitToDos[] = TEXT("NoRealMode"); TCHAR const c_szEnforceSSE[] = TEXT("EnforceShellExtensionSecurity"); TCHAR const c_szNoCommonGroups[] = TEXT("NoCommonGroups"); TCHAR const c_szNoTrayContextMenu[] = TEXT("NoTrayContextMenu"); TCHAR const c_szNoViewContextMenu[] = TEXT("NoViewContextMenu"); TCHAR const c_szNoNetConnectDisconnect[] = TEXT("NoNetConnectDisconnect"); RESTRICTIONITEMS c_rgRestrictionItems[] = { {REST_NORUN, -1, c_szExplorer, c_szNoRun}, {REST_NOCLOSE, -1, c_szExplorer, c_szNoClose}, {REST_NOSAVESET , -1, c_szExplorer, c_szNoSaveSettings}, {REST_NOFILEMENU, -1, c_szExplorer, c_szNoFileMenu}, {REST_NOSETFOLDERS, -1, c_szExplorer, c_szNoSetFolders}, {REST_NOSETTASKBAR, -1, c_szExplorer, c_szNoSetTaskbar}, {REST_NODESKTOP, -1, c_szExplorer, c_szNoDesktop}, {REST_NOFIND, -1, c_szExplorer, c_szNoFind}, {REST_NODRIVES, -1, c_szExplorer, c_szNoDrives}, {REST_NODRIVEAUTORUN, -1, c_szExplorer, c_szNoDriveAutoRun}, {REST_NODRIVETYPEAUTORUN, -1, c_szExplorer, c_szNoDriveTypeAutoRun}, {REST_NONETHOOD, -1, c_szExplorer, c_szNoNetHood}, {REST_STARTBANNER, -1, c_szExplorer, c_szNoStartBanner}, {REST_RESTRICTRUN, -1, c_szExplorer, REGSTR_VAL_RESTRICTRUN}, {REST_NOPRINTERTABS, -1, c_szExplorer, REGSTR_VAL_PRINTERS_HIDETABS}, {REST_NOPRINTERDELETE, -1, c_szExplorer, REGSTR_VAL_PRINTERS_NODELETE}, {REST_NOPRINTERADD, -1, c_szExplorer, REGSTR_VAL_PRINTERS_NOADD}, {REST_NOSTARTMENUSUBFOLDERS, -1, c_szExplorer, c_szNoStartMenuSubFolders}, {REST_MYDOCSONNET, -1, c_szExplorer, c_szMyDocsOnNet}, {REST_NOEXITTODOS, -1, TEXT("WinOldApp"), c_szNoExitToDos}, {REST_ENFORCESHELLEXTSECURITY, -1, c_szExplorer, c_szEnforceSSE}, {REST_NOCOMMONGROUPS, -1, c_szExplorer, c_szNoCommonGroups}, {REST_LINKRESOLVEIGNORELINKINFO, -1, c_szExplorer, TEXT("LinkResolveIgnoreLinkInfo")}, {REST_NOTRAYCONTEXTMENU, -1, c_szExplorer, c_szNoTrayContextMenu}, {REST_NOVIEWCONTEXTMENU, -1, c_szExplorer, c_szNoViewContextMenu}, {REST_NONETCONNECTDISCONNECT, -1, c_szExplorer, c_szNoNetConnectDisconnect} }; //---------------------------------------------------------------------------- // Returns DWORD vaolue if any of the specified restrictions are in place. // 0 otherwise. DWORD WINAPI SHRestricted(RESTRICTIONS rest) { int i; DWORD dw = 0; HKEY hkeyPolicies; TCHAR szSubKey[ARRAYSIZE(REGSTR_PATH_POLICIES) + 40]; // 40 for subkey length DWORD dwSize, dwType; // // Loop through the restrictions // for (i=0; i < ARRAYSIZE(c_rgRestrictionItems); i++) { if (rest & c_rgRestrictionItems[i].uFlag) { // // Has this restriction been initialized yet? // if (c_rgRestrictionItems[i].nValue == -1) { // // This restriction hasn't been read yet. // lstrcpy (szSubKey, REGSTR_PATH_POLICIES); lstrcat (szSubKey, TEXT("\\")); lstrcat (szSubKey, c_rgRestrictionItems[i].pszKey); if (RegOpenKeyEx(HKEY_CURRENT_USER, szSubKey, 0, KEY_READ, &hkeyPolicies) == ERROR_SUCCESS) { dwSize = sizeof(c_rgRestrictionItems[i].nValue); if (RegQueryValueEx (hkeyPolicies, c_rgRestrictionItems[i].pszValue, NULL, &dwType, (LPBYTE) &c_rgRestrictionItems[i].nValue, &dwSize) == ERROR_SUCCESS) { dw = c_rgRestrictionItems[i].nValue; } RegCloseKey (hkeyPolicies); } } else { // // This restriction has been read before. // Use the cached value. // dw = c_rgRestrictionItems[i].nValue; } } } return dw; } #ifdef DEBUG //----------------------------------------------------------------------------- // A set of useful registry key debugging helper functions. They allow the // registry key names to be retrieved from some debugger extensions that we've // written. See SDE.DLL in the shellext directory //----------------------------------------------------------------------------- typedef struct _KEY_NODE { HKEY hKey; LPTSTR lpName; struct _KEY_NODE * next; } KEY_NODE, *LPKEY_NODE; KEY_NODE _reghead = {(HKEY)0xFFFFFFFF, NULL, NULL}; LPKEY_NODE RegKeyHead = &_reghead; BOOL fRegListInit = FALSE; void DebugAddRegKey( HKEY hKey, LPTSTR lpKeyName ) { LPKEY_NODE tmp; tmp = LocalAlloc( LPTR, SIZEOF(KEY_NODE) ); Assert( tmp ); tmp->lpName = (LPTSTR)LocalAlloc( LPTR, (lstrlen(lpKeyName)+1)*SIZEOF(TCHAR) ); Assert( tmp->lpName ); tmp->hKey = hKey; lstrcpy( tmp->lpName, lpKeyName ); ENTERCRITICAL; tmp->next = RegKeyHead->next; RegKeyHead->next = tmp; LEAVECRITICAL; } LPTSTR DebugFindRegKey( HKEY hKey ) { LPTSTR lpRetStr = NULL; LPKEY_NODE tmp; if (!fRegListInit) { DebugAddRegKey( HKEY_CLASSES_ROOT, TEXT("HKEY_CLASSES_ROOT") ); DebugAddRegKey( HKEY_CURRENT_USER, TEXT("HKEY_CURRENT_USER") ); DebugAddRegKey( HKEY_LOCAL_MACHINE, TEXT("HKEY_LOCAL_MACHINE") ); DebugAddRegKey( HKEY_USERS, TEXT("HKEY_USERS") ); fRegListInit = TRUE; } ENTERCRITICAL; tmp = RegKeyHead; while( tmp ) { if ((tmp->hKey!=(HKEY)(0xFFFFFFFF)) && (tmp->hKey == hKey)) { lpRetStr = tmp->lpName; break; } tmp = tmp->next; } LEAVECRITICAL; return lpRetStr; } void DebugDelRegKey( HKEY hKey ) { LPKEY_NODE tmp; LPKEY_NODE tmp2, tmp3; ENTERCRITICAL; tmp = RegKeyHead; while( tmp->next && (tmp->next->hKey!=hKey)) tmp = tmp->next; if (tmp->next) { tmp2 = tmp->next; tmp3 = tmp2->next; tmp->next = tmp3; LocalFree( tmp2->lpName ); LocalFree( tmp2 ); } LEAVECRITICAL; } #else #define DebugFindRegKey(x) NULL #define DebugAddRegKey(x) #define DebugDelRegKey(x) #endif LONG SHRegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD dwReserved, REGSAM samDesired, PHKEY phkResult) { LONG l; l = RegOpenKeyExA(hKey, lpSubKey, dwReserved, samDesired, phkResult); if ( l != ERROR_SUCCESS ) { *phkResult = NULL; } #ifdef DEBUG if ( l == ERROR_SUCCESS ) { TCHAR szTemp[ 1024 ]; LPTSTR lpTmp; lpTmp = DebugFindRegKey( hKey ); if (!lpTmp) { wsprintf( szTemp, TEXT("0x%x"), hKey ); DebugAddRegKey( hKey, szTemp ); } else { lstrcpy( szTemp, lpTmp ); } lstrcat( szTemp, TEXT("\\" )); if (lpSubKey) { #ifdef UNICODE WCHAR szSub[ 1024 ]; MultiByteToWideChar( CP_ACP, 0, lpSubKey, -1, szSub, 1024 ); lstrcat( szTemp, szSub ); #else lstrcat( szTemp, lpSubKey ); #endif } else lstrcat( szTemp, TEXT("NULL") ); if (phkResult!=NULL) DebugAddRegKey( *phkResult, szTemp ); DebugMsg( DM_REG, TEXT("SHRegOpenKeyExA( %s ) == 0x%lx"), szTemp, *phkResult ); } #endif return l; } LONG SHRegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) { LONG l; l = SHRegOpenKeyExA(hKey, lpSubKey, 0L, MAXIMUM_ALLOWED, phkResult); if ( l != ERROR_SUCCESS ) { *phkResult = NULL; } return l; } LONG SHRegCloseKey(HKEY hKey) { LONG l; #undef RegCloseKey l = RegCloseKey(hKey); #ifdef DEBUG { LPTSTR lpReg; lpReg = DebugFindRegKey( hKey ); if (lpReg) DebugMsg( DM_REG, TEXT("SHRegCloseKey( %s ) 0x%lx"), lpReg, hKey ); else DebugMsg( DM_REG, TEXT("SHRegCloseKey( NULL STRING ) 0x%lx"), hKey ); } #endif DebugDelRegKey( hKey ); return l; } LONG SHRegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData) { LONG l; DWORD cbSize; DWORD dwType; LPSTR lpsz; // // two main cases - 1 - they are trying to find out how big of a buffer // to use, 2 - they are actually trying to get data back. // if ( lpData ) { // // Trying to get back data // cbSize = *lpcbData; // Size of output buffer l = RegQueryValueExA(hKey,lpValueName,lpReserved,&dwType,lpData,&cbSize); if ( l == ERROR_SUCCESS && dwType == REG_SZ ) { if (cbSize < *lpcbData) { LPSTR lpszData = (LPSTR)lpData; lpszData[cbSize] = '\0'; } } if ( l == ERROR_SUCCESS && dwType == REG_EXPAND_SZ ) { // // Expand the string // lpsz = (LPSTR)LocalAlloc( LPTR, *lpcbData ); // Size of their buff if ( !lpsz ) { return ERROR_OUTOFMEMORY; } cbSize = ExpandEnvironmentStringsA((LPSTR)lpData,lpsz,*lpcbData); if ( cbSize > 0 && cbSize <= *lpcbData ) { DebugMsg( DM_REG, TEXT("SHRegQueryValueExA expanded (%hs) to %(hs)"), lpData, lpsz ); lstrcpynA( (LPSTR)lpData, lpsz, *lpcbData ); } else { l = GetLastError(); } LocalFree(lpsz); // // Massage dwType so that callers always see REG_SZ // dwType = REG_SZ; } } else { // // Trying to find out how big of a buffer to use // cbSize = 0; l = RegQueryValueExA(hKey,lpValueName,lpReserved,&dwType,NULL,&cbSize); if ( l == ERROR_SUCCESS && dwType == REG_EXPAND_SZ ) { CHAR szBuff[1]; // // Find out the length of the expanded string // lpsz = (LPSTR)LocalAlloc( LPTR, cbSize ); if ( !lpsz ) { return ERROR_OUTOFMEMORY; } l = RegQueryValueExA(hKey,lpValueName,lpReserved,NULL,(LPBYTE)lpsz,&cbSize); if ( l == ERROR_SUCCESS ) { cbSize = ExpandEnvironmentStringsA(lpsz,szBuff,ARRAYSIZE(szBuff)); } LocalFree(lpsz); // // Massage dwType so that callers always see REG_SZ // dwType = REG_SZ; } } if ( lpType ) { *lpType = dwType; } if ( lpcbData ) { *lpcbData = cbSize; } #ifdef DEBUG if (dwType==REG_SZ || dwType==REG_EXPAND_SZ) { LPTSTR lpStr; TCHAR szTemp[1024]; lpStr = DebugFindRegKey( hKey ); if (lpStr) lstrcpy( szTemp, lpStr ); else wsprintf( szTemp, TEXT("(Unknown Key ==> 0x%x)"), hKey ); lstrcat( szTemp, TEXT("\\") ); if (lpValueName) { #ifdef UNICODE WCHAR szValue[ 1024 ]; MultiByteToWideChar( CP_ACP, 0, lpValueName, -1, szValue, 1024 ); lstrcat( szTemp, szValue ); #else lstrcat( szTemp, lpValueName ); #endif } if (lpData) DebugMsg( DM_REG, TEXT("SHRegQueryValueExA(%s) returns (%hs), ret=%d"), szTemp, lpData, l ); else DebugMsg( DM_REG, TEXT("SHRegQueryValueExA(%s), ret=%d"), szTemp, l ); } #endif return l; } LONG SHRegQueryValueA(HKEY hKey,LPCSTR lpSubKey, LPSTR lpValue, PLONG lpcbValue) { LONG l; DWORD dwType; HKEY ChildKey; if ((lpSubKey==NULL) || (*lpSubKey==(CHAR)0)) { ChildKey = hKey; } else { l = SHRegOpenKeyExA( hKey, lpSubKey, 0, KEY_QUERY_VALUE, &ChildKey ); if (l!=ERROR_SUCCESS) return l; } l = SHRegQueryValueExA( ChildKey, NULL, NULL, &dwType, (LPBYTE)lpValue, (LPDWORD)lpcbValue ); if (ChildKey!=hKey) SHRegCloseKey( ChildKey ); if (l == ERROR_FILE_NOT_FOUND) { if (lpValue) *lpValue = (CHAR)0; if (lpcbValue) *lpcbValue = SIZEOF(CHAR); l = ERROR_SUCCESS; } return l; } LONG SHRegOpenKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult) { LONG l; l = SHRegOpenKeyExW(hKey, lpSubKey, 0L, MAXIMUM_ALLOWED, phkResult); if ( l != ERROR_SUCCESS ) { *phkResult = NULL; } return l; } LONG SHRegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD dwReserved, REGSAM samDesired, PHKEY phkResult) { LONG l; l = RegOpenKeyExW(hKey, lpSubKey, dwReserved, samDesired, phkResult); if ( l != ERROR_SUCCESS ) { *phkResult = NULL; } #ifdef DEBUG if (l == ERROR_SUCCESS ) { TCHAR szTemp[ 1024 ]; LPTSTR lpTmp; lpTmp = DebugFindRegKey( hKey ); if (!lpTmp) { wsprintf( szTemp, TEXT("0x%x"), hKey ); DebugAddRegKey( hKey, szTemp ); } else { lstrcpy( szTemp, lpTmp ); } lstrcat( szTemp, TEXT("\\" )); if (lpSubKey) { #ifdef UNICODE lstrcat( szTemp, lpSubKey ); #else CHAR szSub[ 1024 ]; WideCharToMultiByte( CP_ACP, 0, lpSubKey, -1, szSub, 1024, NULL, NULL ); lstrcat( szTemp, szSub ); #endif } else { lstrcat( szTemp, TEXT("NULL") ); } if (phkResult!=NULL) DebugAddRegKey( *phkResult, szTemp ); DebugMsg( DM_REG, TEXT("SHRegOpenKeyExW( %s ) == 0x%lx"), szTemp, *phkResult ); } #endif return l; } LONG SHRegQueryValueExW(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData) { LONG l; DWORD cbSize; DWORD dwType; LPWSTR lpsz; // // two main cases - 1 - they are trying to find out how big of a buffer // to use, 2 - they are actually trying to get data back. // if ( lpData ) { // // Trying to get back data // cbSize = *lpcbData; // Size of output buffer l = RegQueryValueExW(hKey,lpValueName,lpReserved,&dwType,lpData,&cbSize); if ( l == ERROR_SUCCESS && dwType == REG_SZ ) { if (cbSize+SIZEOF(WCHAR) <= *lpcbData) { LPWSTR lpszData = (LPWSTR)lpData; lpszData[cbSize/SIZEOF(WCHAR)] = '\0'; } } if ( l == ERROR_SUCCESS && dwType == REG_EXPAND_SZ ) { // // Expand the string // lpsz = (LPWSTR)LocalAlloc( LPTR, *lpcbData ); // Size of their buff if ( !lpsz ) { return ERROR_OUTOFMEMORY; } cbSize = ExpandEnvironmentStringsW((LPWSTR)lpData,lpsz,*lpcbData/SIZEOF(WCHAR))*SIZEOF(WCHAR); if ( cbSize > 0 && cbSize <= *lpcbData ) { DebugMsg( DM_REG, TEXT("SHRegQueryValueExA expanded (%hs) to %(hs)"), lpData, lpsz ); lstrcpynW( (LPWSTR)lpData, lpsz, *lpcbData/SIZEOF(WCHAR) ); } else { l = GetLastError(); } LocalFree(lpsz); // // Massage dwType so that callers always see REG_SZ // dwType = REG_SZ; } } else { // // Trying to find out how big of a buffer to use // cbSize = 0; l = RegQueryValueExW(hKey,lpValueName,lpReserved,&dwType,NULL,&cbSize); if ( l == ERROR_SUCCESS && dwType == REG_EXPAND_SZ ) { WCHAR szBuff[1]; // // Find out the length of the expanded string // lpsz = (LPWSTR)LocalAlloc( LPTR, cbSize ); if ( !lpsz ) { return ERROR_OUTOFMEMORY; } l = RegQueryValueExW(hKey,lpValueName,lpReserved,NULL,(LPBYTE)lpsz,&cbSize); if ( l == ERROR_SUCCESS ) { cbSize = ExpandEnvironmentStringsW(lpsz,szBuff,ARRAYSIZE(szBuff))*SIZEOF(WCHAR); } LocalFree(lpsz); // // Massage dwType so that callers always see REG_SZ // dwType = REG_SZ; } } if ( lpType ) { *lpType = dwType; } if ( lpcbData ) { *lpcbData = cbSize; } #ifdef DEBUG if (dwType==REG_SZ || dwType==REG_EXPAND_SZ) { LPTSTR lpStr; TCHAR szTemp[1024]; lpStr = DebugFindRegKey( hKey ); if (lpStr) lstrcpy( szTemp, lpStr ); else wsprintf( szTemp, TEXT("(Unknown Key ==> 0x%x)"), hKey ); lstrcat( szTemp, TEXT("\\") ); if (lpValueName) { #ifdef UNICODE lstrcat( szTemp, lpValueName ); #else CHAR szValue[ 1024 ]; WideCharToMultiByte( CP_ACP, 0, lpValueName, -1, szValue, 1024, NULL, NULL ); lstrcat( szTemp, szValue ); #endif } if (lpData) DebugMsg( DM_REG, TEXT("SHRegQueryValueExW(%s) returns (%ls), ret=%d"), szTemp, lpData, l ); else DebugMsg( DM_REG, TEXT("SHRegQueryValueExW(%s), ret=%d"), szTemp, l ); } #endif return l; } LONG SHRegQueryValueW(HKEY hKey,LPCWSTR lpSubKey, LPWSTR lpValue, PLONG lpcbValue) { LONG l; DWORD dwType; HKEY ChildKey; if ((lpSubKey==NULL) || (*lpSubKey==(WCHAR)0)) { ChildKey = hKey; } else { l = RegOpenKeyExW( hKey, lpSubKey, 0, KEY_QUERY_VALUE, &ChildKey ); if (l!=ERROR_SUCCESS) return l; } l = SHRegQueryValueExW( ChildKey, NULL, NULL, &dwType, (LPBYTE)lpValue, (LPDWORD)lpcbValue ); if (ChildKey!=hKey) SHRegCloseKey( ChildKey ); if (l == ERROR_FILE_NOT_FOUND) { if (lpValue) *lpValue = (WCHAR)0; if (lpcbValue) *lpcbValue = SIZEOF(WCHAR); l = ERROR_SUCCESS; } return l; } void SHRegCloseKeys(HKEY ahkeys[], UINT ckeys) { UINT ikeys; for (ikeys=0; ikeys #endif // defined(FULL_DEBUG)