Leaked source code of windows server 2003
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.
 
 
 
 
 
 

907 lines
28 KiB

//
// Random stuff
//
//
#include "priv.h"
#include "exdisp.h"
#include "mshtml.h"
#include "htiframe.h"
#include "util.h"
#include "resource.h"
#include "appwizid.h"
#define CPP_FUNCTIONS
#include <crtfree.h> // declare new, delete, etc.
#define DATEFORMAT_MAX 40
#include <shguidp.h>
#include <ieguidp.h>
// is this okay to do?
#ifdef ENTERCRITICAL
#undef ENTERCRITICAL
#endif
#ifdef LEAVECRITICAL
#undef LEAVECRITICAL
#endif
#define ENTERCRITICAL
#define LEAVECRITICAL
#include "..\inc\uassist.cpp"
// Prototype
BOOL _IsARPAllowed(void);
const VARIANT c_vaEmpty = {0};
#define PVAREMPTY ((VARIANT*)&c_vaEmpty)
STDAPI OpenAppMgr(HWND hwnd, int nPage)
{
HRESULT hres = E_FAIL;
// Make sure we aren't restricted
if (!_IsARPAllowed())
{
ShellMessageBox(g_hinst, hwnd, MAKEINTRESOURCE(IDS_RESTRICTION),
MAKEINTRESOURCE(IDS_NAME), MB_OK | MB_ICONEXCLAMATION);
}
else if ((nPage >= 0) && (nPage < NUMSTARTPAGES))
{
ARP(hwnd, nPage);
hres = S_OK;
}
return hres;
}
inline void StrFree(LPWSTR psz)
{
if (psz)
SHFree(psz);
}
/*-------------------------------------------------------------------------
Purpose: Clear the given app data structure. Frees any allocated fields.
*/
void ClearAppInfoData(APPINFODATA * pdata)
{
if (pdata)
{
if (pdata->dwMask & AIM_DISPLAYNAME)
StrFree(pdata->pszDisplayName);
if (pdata->dwMask & AIM_VERSION)
StrFree(pdata->pszVersion);
if (pdata->dwMask & AIM_PUBLISHER)
StrFree(pdata->pszPublisher);
if (pdata->dwMask & AIM_PRODUCTID)
StrFree(pdata->pszProductID);
if (pdata->dwMask & AIM_REGISTEREDOWNER)
StrFree(pdata->pszRegisteredOwner);
if (pdata->dwMask & AIM_REGISTEREDCOMPANY)
StrFree(pdata->pszRegisteredCompany);
if (pdata->dwMask & AIM_LANGUAGE)
StrFree(pdata->pszLanguage);
if (pdata->dwMask & AIM_SUPPORTURL)
StrFree(pdata->pszSupportUrl);
if (pdata->dwMask & AIM_SUPPORTTELEPHONE)
StrFree(pdata->pszSupportTelephone);
if (pdata->dwMask & AIM_HELPLINK)
StrFree(pdata->pszHelpLink);
if (pdata->dwMask & AIM_INSTALLLOCATION)
StrFree(pdata->pszInstallLocation);
if (pdata->dwMask & AIM_INSTALLSOURCE)
StrFree(pdata->pszInstallSource);
if (pdata->dwMask & AIM_INSTALLDATE)
StrFree(pdata->pszInstallDate);
if (pdata->dwMask & AIM_CONTACT)
StrFree(pdata->pszContact);
if (pdata->dwMask & AIM_COMMENTS)
StrFree(pdata->pszComments);
if (pdata->dwMask & AIM_IMAGE)
StrFree(pdata->pszImage);
}
}
void ClearSlowAppInfo(SLOWAPPINFO * pdata)
{
if (pdata)
{
StrFree(pdata->pszImage);
pdata->pszImage = NULL;
}
}
// NOTE: Returns TRUE only if psaiNew has valid info and different from psaiOrig
BOOL IsSlowAppInfoChanged(PSLOWAPPINFO psaiOrig, PSLOWAPPINFO psaiNew)
{
BOOL bRet = FALSE;
ASSERT(psaiOrig && psaiNew);
if (psaiNew)
{
// Compare size first
if (psaiOrig == NULL)
{
bRet = TRUE;
}
else if (((__int64)psaiNew->ullSize > 0) && (psaiNew->ullSize != psaiOrig->ullSize))
{
bRet = TRUE;
}
// Now compare the file time
else if (((0 != psaiNew->ftLastUsed.dwHighDateTime) &&
(psaiOrig->ftLastUsed.dwHighDateTime != psaiNew->ftLastUsed.dwHighDateTime))
|| ((0 != psaiNew->ftLastUsed.dwLowDateTime) &&
(psaiOrig->ftLastUsed.dwLowDateTime != psaiNew->ftLastUsed.dwLowDateTime)))
{
bRet = TRUE;
}
// Compare times used
else if (psaiOrig->iTimesUsed != psaiNew->iTimesUsed)
{
bRet = TRUE;
}
// Compare the icon image
else if ((psaiNew->pszImage != NULL) && (psaiOrig->pszImage != NULL) && lstrcmpi(psaiNew->pszImage, psaiOrig->pszImage))
bRet = TRUE;
}
return bRet;
}
void ClearManagedApplication(MANAGEDAPPLICATION * pma)
{
if (pma)
{
if (pma->pszPackageName)
LocalFree(pma->pszPackageName);
if (pma->pszPublisher)
LocalFree(pma->pszPublisher);
if (pma->pszPolicyName)
LocalFree(pma->pszPolicyName);
if (pma->pszOwner)
LocalFree(pma->pszOwner);
if (pma->pszCompany)
LocalFree(pma->pszCompany);
if (pma->pszComments)
LocalFree(pma->pszComments);
if (pma->pszContact)
LocalFree(pma->pszContact);
}
}
/*-------------------------------------------------------------------------
Purpose: Clear the given PUBAPPINFO data structure. Frees any allocated fields.
*/
void ClearPubAppInfo(PUBAPPINFO * pdata)
{
if (pdata)
{
if ((pdata->dwMask & PAI_SOURCE) && pdata->pszSource)
StrFree(pdata->pszSource);
}
}
/*-------------------------------------------------------------------------
Purpose: Frees a specific category structure
*/
HRESULT ReleaseShellCategory(SHELLAPPCATEGORY * psac)
{
ASSERT(psac);
if (psac->pszCategory)
{
SHFree(psac->pszCategory);
psac->pszCategory = NULL;
}
return S_OK;
}
/*-------------------------------------------------------------------------
Purpose: Frees the list of categories
*/
HRESULT ReleaseShellCategoryList(SHELLAPPCATEGORYLIST * psacl)
{
UINT i;
SHELLAPPCATEGORY * psac;
ASSERT(psacl);
psac = psacl->pCategory;
for (i = 0; i < psacl->cCategories; i++, psac++)
{
ReleaseShellCategory(psac);
}
return S_OK;
}
#define MAX_INT64_SIZE 30 // 2^64 is less than 30 chars long
#define MAX_COMMA_NUMBER_SIZE (MAX_INT64_SIZE + 10)
#define MAX_COMMA_AS_K_SIZE (MAX_COMMA_NUMBER_SIZE + 10)
#define HIDWORD(_qw) (DWORD)((_qw)>>32)
#define LODWORD(_qw) (DWORD)(_qw)
void Int64ToStr( _int64 n, LPTSTR lpBuffer)
{
TCHAR szTemp[MAX_INT64_SIZE];
_int64 iChr;
iChr = 0;
do {
szTemp[iChr++] = TEXT('0') + (TCHAR)(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, UINT cchResult)
{
// FEATURE: We should pass in the lenght on pszResult buffer, we assume 40 will be enough
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);
// Should have passed in size
if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, MAX_COMMA_NUMBER_SIZE) == 0)
{
StringCchCopy(pszResult, cchResult, szTemp);
}
return pszResult;
}
//
// 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)
{
StringCchPrintf(szTemp, ARRAYSIZE(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, ARRAYSIZE(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.
StringCchCopy(szFormat, ARRAYSIZE(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));
StringCchPrintf(szBuf, ARRAYSIZE(szBuf), szOrder, (LPTSTR)szTemp);
return szBuf;
}
#define c_szUninstallPolicy L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Uninstall"
/*-------------------------------------------------------------------------
Purpose: Helper function for ARP's policy check
*/
DWORD ARPGetRestricted(LPCWSTR pszPolicy)
{
return SHGetRestriction(NULL, TEXT("Uninstall"), pszPolicy);
}
/*-------------------------------------------------------------------------
Purpose: Return a policy string value
*/
void ARPGetPolicyString(LPCWSTR pszPolicy, LPWSTR pszBuf, int cch)
{
DWORD dwSize, dwType;
*pszBuf = 0;
// Check local machine first and let it override what the
// HKCU policy has done.
dwSize = cch * sizeof(WCHAR);
if (ERROR_SUCCESS != SHGetValueW(HKEY_LOCAL_MACHINE,
c_szUninstallPolicy, pszPolicy,
&dwType, pszBuf, &dwSize))
{
// Check current user if we didn't find anything for the local machine.
dwSize = cch * sizeof(WCHAR);
SHGetValueW(HKEY_CURRENT_USER,
c_szUninstallPolicy, pszPolicy,
&dwType, pszBuf, &dwSize);
}
}
/*-------------------------------------------------------------------------
Purpose: Returns TRUE if it's okay to start ARP.
*/
BOOL _IsARPAllowed(void)
{
// ARP is forbidden if the entire CPL is disabled
if (ARPGetRestricted(L"NoAddRemovePrograms"))
{
return FALSE;
}
// ARP is permitted if there exists a non-restricted page.
BOOL fAnyPages = !ARPGetRestricted(L"NoRemovePage") ||
!ARPGetRestricted(L"NoAddPage") ||
!ARPGetRestricted(L"NoWindowsSetupPage");
// If we are not a server SKU, then also check the new page.
if (!fAnyPages && !IsOS(OS_ANYSERVER))
{
fAnyPages = !ARPGetRestricted(L"NoChooseProgramsPage");
}
return fAnyPages;
}
/*-------------------------------------------------------------------------
Purpose: Take the error message and give user feedback through messagebox
*/
void _ARPErrorMessageBox(DWORD dwError)
{
TCHAR szErrorMsg[MAX_PATH];
szErrorMsg[0] = 0;
LPTSTR pszMsg = NULL;
switch (dwError) {
// The following error code cases are ignored.
case ERROR_INSTALL_USEREXIT:
case ERROR_SUCCESS_REBOOT_REQUIRED:
case ERROR_SUCCESS_REBOOT_INITIATED:
ASSERT(pszMsg == NULL);
break;
default:
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0L, szErrorMsg,
ARRAYSIZE(szErrorMsg), NULL);
pszMsg = szErrorMsg;
break;
}
if (pszMsg)
{
ShellMessageBox( g_hinst, NULL, pszMsg,
MAKEINTRESOURCE( IDS_NAME ),
MB_OK | MB_ICONEXCLAMATION);
}
}
/*-------------------------------------------------------------------------
Purpose: Format the SYSTEMTIME into the following format: "mm/dd/yy h:mm"
*/
BOOL FormatSystemTimeString(LPSYSTEMTIME pst, LPTSTR pszStr, UINT cchStr)
{
BOOL bRet = FALSE;
FILETIME ft = {0};
if (SystemTimeToFileTime(pst, &ft))
{
DWORD dwFlags = FDTF_SHORTTIME | FDTF_SHORTDATE;
bRet = SHFormatDateTime(&ft, &dwFlags, pszStr, cchStr);
}
return bRet;
}
/*-------------------------------------------------------------------------
Purpose: Get the correct Date time format for specific locale
*/
BOOL _GetLocaleDateTimeFormat(LPTSTR pszFormat, UINT cchFormat)
{
TCHAR szTime[DATEFORMAT_MAX];
TCHAR szDate[DATEFORMAT_MAX];
if (cchFormat >= (ARRAYSIZE(szTime) + ARRAYSIZE(szDate) + 2))
{
LCID lcid = LOCALE_USER_DEFAULT;
if (GetLocaleInfo(lcid, LOCALE_STIMEFORMAT, szTime, ARRAYSIZE(szTime)) &&
GetLocaleInfo(lcid, LOCALE_SSHORTDATE, szDate, ARRAYSIZE(szDate)))
{
StringCchPrintf(pszFormat, cchFormat, TEXT("%s %s"), szDate, szTime);
return TRUE;
}
}
return FALSE;
}
/*-------------------------------------------------------------------------
Purpose: Compare two SYSTEMTIME data
Returnes : 1 : st1 > st2
0 : st1 == st2
-1: st1 < st2
NOTE: We do not compare seconds since ARP does not need that much precision.
*/
int CompareSystemTime(SYSTEMTIME *pst1, SYSTEMTIME *pst2)
{
int iRet;
if (pst1->wYear < pst2->wYear)
iRet = -1;
else if (pst1->wYear > pst2->wYear)
iRet = 1;
else if (pst1->wMonth < pst2->wMonth)
iRet = -1;
else if (pst1->wMonth > pst2->wMonth)
iRet = 1;
else if (pst1->wDay < pst2->wDay)
iRet = -1;
else if (pst1->wDay > pst2->wDay)
iRet = 1;
else if (pst1->wHour < pst2->wHour)
iRet = -1;
else if (pst1->wHour > pst2->wHour)
iRet = 1;
else if (pst1->wMinute < pst2->wMinute)
iRet = -1;
else if (pst1->wMinute > pst2->wMinute)
iRet = 1;
// else if (pst1->wSecond < pst2->wSecond)
// iRet = -1;
// else if (pst1->wSecond > pst2->wSecond)
// iRet = 1;
else
iRet = 0;
return(iRet);
}
/*--------------------------------------------------------------------------
Purpose: Window proc for the add later dialog box
*/
BOOL_PTR CALLBACK AddLaterDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_INITDIALOG:
{
PADDLATERDATA pald = (PADDLATERDATA)lp;
// We should definitely have this (dli)
ASSERT(pald);
SYSTEMTIME stInit = {0};
// Get the current local time
GetLocalTime(&stInit);
// Has this app already expired?
if ((pald->dwMasks & ALD_EXPIRE) &&
(CompareSystemTime(&pald->stExpire, &stInit) > 0))
{
// NO,
// Assigned time does not make sense if the assigned time has already
// passed
if ((pald->dwMasks & ALD_ASSIGNED) &&
(CompareSystemTime(&pald->stAssigned, &stInit) <= 0))
pald->dwMasks &= ~ALD_ASSIGNED;
// find the date/time picker window
HWND hwndPicker = GetDlgItem(hDlg, IDC_PICKER);
// always check "add later" radio button initially
CheckDlgButton(hDlg, IDC_ADDLATER, BST_CHECKED);
TCHAR szFormat[MAX_PATH];
if (_GetLocaleDateTimeFormat(szFormat, ARRAYSIZE(szFormat)))
{
// set the locale date time format
DateTime_SetFormat(hwndPicker, szFormat);
// The new time can only be in the future, so set the current time
// as the lower limit
DateTime_SetRange(hwndPicker, GDTR_MIN, &stInit);
// Do we have a schedule (in the future) already?
// Schedule in the past means nothing
if ((pald->dwMasks & ALD_SCHEDULE) &&
(CompareSystemTime(&pald->stSchedule, &stInit) >= 0))
{
// Set our initial value to this schedule
stInit = pald->stSchedule;
}
// Set the initial value in date/time picker
DateTime_SetSystemtime(hwndPicker, GDT_VALID, &stInit);
// Uncheck the SCHEDULE flag so that we know we don't have a new
// schedule, yet
pald->dwMasks &= ~ALD_SCHEDULE;
SetWindowLongPtr(hDlg, DWLP_USER, lp);
return TRUE;
}
}
else
{
// Yes, it's expired, warn the user
ShellMessageBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_EXPIRED),
MAKEINTRESOURCE(IDS_NAME), MB_OK | MB_ICONEXCLAMATION);
// Then end the dialog.
EndDialog(hDlg, 0);
}
return FALSE;
}
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wp, lp))
{
case IDC_ADDLATER:
case IDC_UNSCHEDULE:
{
HWND hwndPicker = GetDlgItem(hDlg, IDC_PICKER);
EnableWindow(hwndPicker, IsDlgButtonChecked(hDlg, IDC_ADDLATER));
}
break;
case IDOK:
{
PADDLATERDATA pald = (PADDLATERDATA)GetWindowLongPtr(hDlg, DWLP_USER);
// we did set window long ptr this should be there.
ASSERT(pald);
// did the user choose to add later?
if (IsDlgButtonChecked(hDlg, IDC_ADDLATER))
{
// Yes
// Let's find out if the time user has chosen is valid
#define LATER_THAN_ASSIGNED_TIME 1
#define LATER_THAN_EXPIRED_TIME 2
int iStatus = 0;
HWND hwndPicker = GetDlgItem(hDlg, IDC_PICKER);
DateTime_GetSystemtime(hwndPicker, &pald->stSchedule);
// Is this time later than the assigned time?
if ((pald->dwMasks & ALD_ASSIGNED) &&
(CompareSystemTime(&pald->stSchedule, &pald->stAssigned) > 0))
iStatus = LATER_THAN_ASSIGNED_TIME;
// Is this time later than the expired time?
if ((pald->dwMasks & ALD_EXPIRE) &&
(CompareSystemTime(&pald->stSchedule, &pald->stExpire) >= 0))
iStatus = LATER_THAN_EXPIRED_TIME;
// Is either of the above two cases TRUE?
if (iStatus > 0)
{
TCHAR szDateTime[MAX_PATH];
// Is the time user chose passed expired time or assigned?
BOOL bExpired = (iStatus == LATER_THAN_EXPIRED_TIME);
// Get the time string
if (FormatSystemTimeString(bExpired ? &pald->stExpire : &pald->stAssigned,
szDateTime, ARRAYSIZE(szDateTime)))
{
TCHAR szFinal[MAX_PATH * 2];
TCHAR szWarn[MAX_PATH];
LoadString(g_hinst, bExpired ? IDS_PASSEXPIRED : IDS_PASSASSIGNED,
szWarn, ARRAYSIZE(szWarn));
StringCchPrintf(szFinal, ARRAYSIZE(szFinal), szWarn, szDateTime, szDateTime);
ShellMessageBox(g_hinst, hDlg, szFinal,
MAKEINTRESOURCE(IDS_NAME), MB_OK | MB_ICONEXCLAMATION);
}
}
else
// No, we are okay to go
pald->dwMasks |= ALD_SCHEDULE;
}
}
//
// fall through
//
case IDCANCEL:
EndDialog(hDlg, (GET_WM_COMMAND_ID(wp, lp) == IDOK));
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
/*-------------------------------------------------------------------------
Purpose: GetNewInstallTime
Start up the Add Later dialog box to get the new install schedule
(represented by a SYSTEMTIME data struct)
*/
BOOL GetNewInstallTime(HWND hwndParent, PADDLATERDATA pal)
{
return (DialogBoxParam(g_hinst, MAKEINTRESOURCE(DLG_ADDLATER),
hwndParent, AddLaterDlgProc, (LPARAM)pal) == IDOK);
}
// Take the name of the potential app folder and see if it ends with numbers or dots
// if it does, let's separate the numbers and see if there is a match.
// It's inspired by cases like Office8.0 or MSVC50 or Bookshelf98
// NOTE: we can't use the key words without the numbers, it might lead to mistake
// in case the user has two versions of the same software on one machine. (there might
// be something we can do though, I am too tired to think about this now)
void InsertSpaceBeforeVersion(LPCTSTR pszIn, LPTSTR pszOut)
{
ASSERT(IS_VALID_STRING_PTR(pszIn, -1));
ASSERT(IS_VALID_STRING_PTR(pszOut, -1));
// Copy the old string into the buffer
lstrcpy(pszOut, pszIn);
// Find the end of the string
LPTSTR pszEnd = pszOut + lstrlen(pszOut);
ASSERT(pszEnd > pszOut);
// Go back until we can't see numbers or '.'
LPTSTR pszLastChar = CharPrev(pszOut, pszEnd);
LPTSTR pszPrev = pszLastChar;
while ((pszPrev > pszOut) && (((*pszPrev <= TEXT('9')) && (*pszPrev >= TEXT('0'))) || (*pszPrev == TEXT('.'))))
pszPrev = CharPrev(pszOut, pszPrev);
// Did we find any numbers at the end?
if ((pszPrev < pszLastChar) && IsCharAlphaNumeric(*pszPrev))
{
// Yes, let's stick a ' ' in between
TCHAR szNumbers[MAX_PATH];
StringCchCopy(szNumbers, ARRAYSIZE(szNumbers), ++pszPrev);
*(pszPrev++) = TEXT(' ');
lstrcpy(pszPrev, szNumbers);
}
}
//
// Basic sanity check on whether the app folder location is valid.
// Return Value:
// TRUE does not mean it is valid.
// FALSE means it definitely is not valid.
//
BOOL IsValidAppFolderLocation(LPCTSTR pszFolder)
{
ASSERT(IS_VALID_STRING_PTR(pszFolder, -1));
BOOL bRet = FALSE;
if (!PathIsRoot(pszFolder) && PathFileExists(pszFolder) && PathIsDirectory(pszFolder))
{
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(StringCchCopy(szPath, ARRAYSIZE(szPath), pszFolder)) && PathStripToRoot(szPath))
{
bRet = (GetDriveType(szPath) == DRIVE_FIXED);
}
}
return bRet;
}
EXTERN_C BOOL IsTerminalServicesRunning(void)
{
static int s_fIsTerminalServer = -1;
if (s_fIsTerminalServer == -1)
{
BOOL TSAppServer;
BOOL TSRemoteAdmin;
OSVERSIONINFOEX osVersionInfo;
DWORDLONG dwlConditionMask = 0;
ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL;
VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
TSAppServer = (int)VerifyVersionInfo(&osVersionInfo, VER_SUITENAME, dwlConditionMask);
ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osVersionInfo.wSuiteMask = VER_SUITE_SINGLEUSERTS;
VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
TSRemoteAdmin = (int)VerifyVersionInfo(&osVersionInfo, VER_SUITENAME, dwlConditionMask);
if ( !TSRemoteAdmin && TSAppServer )
{
s_fIsTerminalServer = TRUE;
}
else
{
// do not treat tsremoteadmin as TS machine from the application compatability point of view.
s_fIsTerminalServer = FALSE;
}
}
return s_fIsTerminalServer ? TRUE : FALSE;
}
// returns TRUE if pszFile is a local file and on a fixed drive
BOOL PathIsLocalAndFixed(LPCTSTR pszFile)
{
if (!pszFile || !pszFile[0])
return FALSE;
if (PathIsUNC(pszFile))
return FALSE;
TCHAR szDrive[MAX_PATH];
StringCchCopy(szDrive, ARRAYSIZE(szDrive), pszFile);
if (PathStripToRoot(szDrive) && GetDriveType(szDrive) != DRIVE_FIXED)
return FALSE;
return TRUE;
}
// This function will duplicate an APPCATEGORYINFOLIST and allocate the new copy
// using COM memory allocation functions
STDAPI _DuplicateCategoryList(APPCATEGORYINFOLIST * pacl, APPCATEGORYINFOLIST * paclNew)
{
HRESULT hres = E_FAIL;
ASSERT(pacl && paclNew);
ZeroMemory(paclNew, SIZEOF(APPCATEGORYINFOLIST));
if (pacl && (pacl->cCategory > 0) && pacl->pCategoryInfo)
{
DWORD dwDesiredSize = pacl->cCategory * SIZEOF(APPCATEGORYINFO);
APPCATEGORYINFO * paci = pacl->pCategoryInfo;
paclNew->pCategoryInfo = (APPCATEGORYINFO *)SHAlloc(dwDesiredSize);
if (paclNew->pCategoryInfo)
{
UINT iCategory = 0;
paclNew->cCategory = 0;
APPCATEGORYINFO * paciNew = paclNew->pCategoryInfo;
while (paci && (iCategory < pacl->cCategory))
{
if (paci->pszDescription)
{
hmemcpy(paciNew, paci, SIZEOF(APPCATEGORYINFO));
if (FAILED(SHStrDup(paci->pszDescription, &(paciNew->pszDescription))))
{
// We may be out of memory, stop here.
ZeroMemory(paciNew, SIZEOF(APPCATEGORYINFO));
break;
}
paciNew++;
paclNew->cCategory++;
}
iCategory++;
paci++;
}
hres = S_OK;
}
else
hres = E_OUTOFMEMORY;
}
return hres;
}
STDAPI _DestroyCategoryList(APPCATEGORYINFOLIST * pacl)
{
if (pacl && pacl->pCategoryInfo)
{
UINT iCategory = 0;
APPCATEGORYINFO * paci = pacl->pCategoryInfo;
while (paci && (iCategory < pacl->cCategory))
{
if (paci->pszDescription)
{
SHFree(paci->pszDescription);
}
iCategory++;
paci++;
}
SHFree(pacl->pCategoryInfo);
}
return S_OK;
}