Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2234 lines
63 KiB

//---------------------------------------------------------------------------
//
// 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<ARRAYSIZE(pwOrders)-1 && dw64 >= 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<DSA_GetItemCount(pdka->_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; icls<ccls ; icls++)
{
if (IsEqualGUID(rclsid, DCA_GetItem(hdca,icls))) {
return FALSE;
}
}
DSA_InsertItem((HDSA)hdca, INT_MAX, (LPVOID)rclsid);
return TRUE;
}
void DCA_AddItemsFromKey(HDCA hdca, HKEY hkey, LPCTSTR pszSubKey)
{
HDKA hdka = DKA_Create(hkey, pszSubKey, NULL, NULL, FALSE);
if (hdka)
{
int ikey;
int ckey = DKA_GetItemCount(hdka);
for ( ikey=0; ikey<ckey ; ikey++ )
{
HRESULT hres;
CLSID clsid;
//
// First, check if the key itself is a CLSID
//
hres = SHCLSIDFromString(DKA_GetKey(hdka, ikey), &clsid);
if (FAILED(hres))
{
//
// If not, try its value
//
TCHAR szCLSID[MAXPATHLEN];
LONG cb=SIZEOF(szCLSID);
if (DKA_QueryValue(hdka, ikey, szCLSID, &cb)==ERROR_SUCCESS)
{
hres = SHCLSIDFromString(szCLSID, &clsid);
}
}
//
// Add the CLSID if we successfully got the CLSID.
//
if (SUCCEEDED(hres))
{
DCA_AddItem(hdca, &clsid);
}
}
DKA_Destroy(hdka);
}
}
HRESULT DCA_CreateInstance(HDCA hdca, int iItem, REFIID riid, LPVOID FAR* ppv)
{
const CLSID * pclsid = DCA_GetItem(hdca, iItem);
if (pclsid) {
return SHCoCreateInstance(NULL, pclsid, NULL, riid, ppv);
}
return ResultFromScode(E_INVALIDARG);
}
// We use a short integer, such that the size is the same for both
// 16 and 32 bits and no string should exceed 64K
// BUGBUG (DavePl) I'm now assuming that the count of _chars_ is
// written at the head of the stream
HRESULT Stream_ReadStringBuffer(LPSTREAM pstm, LPTSTR psz, UINT cchBuf)
{
USHORT cch;
HRESULT hres;
VDATEINPUTBUF(psz, TCHAR, cchBuf);
hres = pstm->lpVtbl->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<ckeys; ikeys++) {
if (ahkeys[ikeys]) {
SHRegCloseKey(ahkeys[ikeys]);
ahkeys[ikeys]=NULL;
}
}
}
// On Win95, RegDeleteKey deletes the key and all subkeys. On NT, RegDeleteKey
// fails if there are any subkeys. On NT, we'll make shell code that assumes
// the Win95 behavior work by mapping SHRegDeleteKey to a helper function that
// does the recursive delete.
#ifdef WINNT
LONG SHRegDeleteKeyW(HKEY hKey, LPCTSTR lpSubKey)
{
LONG lResult;
HKEY hkSubKey;
DWORD dwIndex;
TCHAR szSubKeyName[MAX_PATH + 1];
DWORD cchSubKeyName = ARRAYSIZE(szSubKeyName);
TCHAR szClass[MAX_PATH];
DWORD cbClass = ARRAYSIZE(szClass);
DWORD dwDummy1, dwDummy2, dwDummy3, dwDummy4, dwDummy5, dwDummy6;
FILETIME ft;
// Open the subkey so we can enumerate any children
lResult = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &hkSubKey);
if (ERROR_SUCCESS == lResult)
{
// I can't just call RegEnumKey with an ever-increasing index, because
// I'm deleting the subkeys as I go, which alters the indices of the
// remaining subkeys in an implementation-dependent way. In order to
// be safe, I have to count backwards while deleting the subkeys.
// Find out how many subkeys there are
lResult = RegQueryInfoKey(hkSubKey,
szClass,
&cbClass,
NULL,
&dwIndex, // The # of subkeys -- all we need
&dwDummy1,
&dwDummy2,
&dwDummy3,
&dwDummy4,
&dwDummy5,
&dwDummy6,
&ft);
if (ERROR_SUCCESS == lResult)
{
// dwIndex is now the count of subkeys, but it needs to be
// zero-based for RegEnumKey, so I'll pre-decrement, rather
// than post-decrement.
while (ERROR_SUCCESS == RegEnumKey(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName))
{
SHRegDeleteKey(hkSubKey, szSubKeyName);
}
}
RegCloseKey(hkSubKey);
lResult = RegDeleteKey(hKey, lpSubKey);
}
return lResult;
}
#endif
//----------------------------------------------------------------------------
BOOL WINAPI SHWinHelp(HWND hwndMain, LPCTSTR lpszHelp, UINT usCommand, DWORD ulData)
{
// Try to show help
if (!WinHelp(hwndMain, lpszHelp, usCommand, ulData))
{
// Problem.
ShellMessageBox(HINST_THISDLL, hwndMain,
MAKEINTRESOURCE(IDS_WINHELPERROR),
MAKEINTRESOURCE(IDS_WINHELPTITLE),
MB_ICONHAND | MB_OK);
return FALSE;
}
return TRUE;
}
//----------------------------------------------------------------------------
HRESULT SHRegGetCLSIDKey(const CLSID * pclsid, LPCTSTR lpszSubKey, BOOL fUserSpecific, HKEY *phkey)
{
HKEY hkeyRef;
TCHAR szThisCLSID[GUIDSTR_MAX];
TCHAR szPath[GUIDSTR_MAX+MAX_PATH+1]; // room for clsid + extra
StringFromGUID2A(pclsid, szThisCLSID, ARRAYSIZE(szThisCLSID));
if (fUserSpecific)
{
hkeyRef = HKEY_CURRENT_USER;
lstrcpy(szPath, c_szSoftwareClassesCLSID);
}
else
{
hkeyRef = HKEY_CLASSES_ROOT;
lstrcpy(szPath, c_szCLSID);
lstrcat(szPath, TEXT("\\"));
}
lstrcat(szPath, szThisCLSID);
if (lpszSubKey)
{
lstrcat(szPath,TEXT("\\"));
lstrcat(szPath,lpszSubKey);
}
if (SHRegOpenKey(hkeyRef, szPath, phkey) != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
return NOERROR;
}
//===========================================================================
#if defined(FULL_DEBUG)
#include <deballoc.c>
#endif // defined(FULL_DEBUG)