795 lines
24 KiB
C++
795 lines
24 KiB
C++
|
/*++
|
||
|
|
||
|
Microsoft Windows
|
||
|
Copyright (C) Microsoft Corporation, 1981 - 1998
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
utils.cxx
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Rahul Thombre (RahulTh) 4/8/1998
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
4/8/1998 RahulTh
|
||
|
|
||
|
Created this module.
|
||
|
|
||
|
--*/
|
||
|
#include "precomp.hxx"
|
||
|
|
||
|
BOOL IsSpecialDescendant (const long nID, UINT* parentID /*= NULL*/)
|
||
|
{
|
||
|
BOOL fRetVal;
|
||
|
int prntID = -1;
|
||
|
|
||
|
switch (nID)
|
||
|
{
|
||
|
case IDS_MYPICS:
|
||
|
prntID = IDS_MYDOCS;
|
||
|
break;
|
||
|
case IDS_PROGRAMS:
|
||
|
prntID = IDS_STARTMENU;
|
||
|
break;
|
||
|
case IDS_STARTUP:
|
||
|
prntID = IDS_PROGRAMS;
|
||
|
break;
|
||
|
default:
|
||
|
prntID = -1;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (fRetVal = (-1 != prntID))
|
||
|
{
|
||
|
if (parentID)
|
||
|
*parentID = prntID;
|
||
|
}
|
||
|
|
||
|
return fRetVal;
|
||
|
}
|
||
|
|
||
|
//this is a helper function for ConvertOldStyleSection(...) which is used
|
||
|
//to convert Beta3 style ini files to Win2K style ini files.
|
||
|
void SplitRHS (CString& szValue, unsigned long & flags, CString& szPath)
|
||
|
{
|
||
|
int index;
|
||
|
|
||
|
//take some precautions
|
||
|
szValue.TrimRight();
|
||
|
szValue.TrimLeft();
|
||
|
szPath.Empty();
|
||
|
flags = 0;
|
||
|
|
||
|
if (szValue.IsEmpty())
|
||
|
return;
|
||
|
|
||
|
//if we are here, szValue at least contains the flags
|
||
|
swscanf ((LPCTSTR)szValue, TEXT("%x"), &flags);
|
||
|
|
||
|
//check if there is a path too.
|
||
|
index = szValue.Find(' '); //we will find a space only if there is a path too.
|
||
|
if (-1 != index) //there is a path too.
|
||
|
{
|
||
|
szPath = szValue.Mid (index + 1);
|
||
|
szPath.TrimLeft();
|
||
|
szPath.TrimRight();
|
||
|
ASSERT (!szPath.IsEmpty());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Given a full path name, this routine extracts its display name, viz.
|
||
|
// the part of which follows the final \. If there are no \'s in the
|
||
|
// full name, then it sets the display name to the full name
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void ExtractDisplayName (const CString& szFullname, CString& szDisplayname)
|
||
|
{
|
||
|
CString szName;
|
||
|
szName = szFullname;
|
||
|
//first get rid of any trailing spaces; this might happen in cases
|
||
|
//where one is trying to create a shortcut to a network drive and
|
||
|
//when resolved to a UNC path, it yields a path ending in a slash
|
||
|
|
||
|
//reverse the string so that any trailing slashes will now be at the
|
||
|
//head of the string
|
||
|
szName.MakeReverse();
|
||
|
//get rid of the leading slashes and spaces of the reversed string
|
||
|
szName = szName.Mid ((szName.SpanIncluding(TEXT("\\ "))).GetLength());
|
||
|
//reverse the string again and we will have a string without
|
||
|
//any trailing '\' or ' '
|
||
|
szName.MakeReverse();
|
||
|
|
||
|
//with the trailing '\' and spaces removed, we can go about the
|
||
|
//business of getting the display name
|
||
|
|
||
|
//if \ cannot be found, ReverseFind returns -1 which gives 0 on adding
|
||
|
//1, therefore szDisplayname gets the entire name if no \ is found.
|
||
|
szDisplayname = szName.Mid (szName.ReverseFind('\\') + 1);
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SplitProfileString
|
||
|
//
|
||
|
// Synopsis: This function takes in a string of the type key=value and
|
||
|
// extracts the key and the value from it.
|
||
|
//
|
||
|
// Arguments: [in] szPair : the key value pair
|
||
|
// [out] szKey : the key
|
||
|
// [out] szValue : the value
|
||
|
//
|
||
|
// Returns: S_OK : if everything goes well.
|
||
|
// E_FAIL: if the '=' sign cannot be found
|
||
|
//
|
||
|
// History: 9/28/1998 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT SplitProfileString (CString szPair, CString& szKey, CString& szValue)
|
||
|
{
|
||
|
int nEqPos;
|
||
|
|
||
|
nEqPos = szPair.Find ('=');
|
||
|
|
||
|
if (-1 == nEqPos)
|
||
|
return E_FAIL;
|
||
|
|
||
|
szKey = szPair.Left(nEqPos);
|
||
|
szKey.TrimLeft();
|
||
|
szKey.TrimRight();
|
||
|
|
||
|
szValue = szPair.Mid (nEqPos + 1);
|
||
|
szValue.TrimLeft();
|
||
|
szValue.TrimRight();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ConvertOldStyleSection
|
||
|
//
|
||
|
// Synopsis: this function looks at an ini file and if does not have the
|
||
|
// new ini file format, it reads the old redirect section and
|
||
|
// transforms it into the new ini file format which supports
|
||
|
// scaleability
|
||
|
//
|
||
|
// Arguments: [in] szGPTPath : the directory where the ini file resides
|
||
|
// [in] pScope : pointer to the scope pane
|
||
|
//
|
||
|
// Returns: S_OK if it was successful
|
||
|
// an error code if it fails
|
||
|
//
|
||
|
// History: 9/28/1998 RahulTh created
|
||
|
//
|
||
|
// Notes: This function exists primarily for backward compatibility
|
||
|
// with Win2K betas. Might be okay to remove it.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT ConvertOldStyleSection (
|
||
|
const CString& szGPTPath
|
||
|
)
|
||
|
{
|
||
|
AFX_MANAGE_STATE (AfxGetStaticModuleState());
|
||
|
|
||
|
CString szIniFile;
|
||
|
TCHAR* lpszSection;
|
||
|
TCHAR* szEntry;
|
||
|
DWORD cbSize = 1024;
|
||
|
DWORD cbCopied;
|
||
|
CString SectionEntry;
|
||
|
CString Key;
|
||
|
CString Dir;
|
||
|
CString Value;
|
||
|
CString Path;
|
||
|
CString szStartMenu;
|
||
|
CString szPrograms;
|
||
|
CString szStartup;
|
||
|
ULONG flags;
|
||
|
DWORD Status;
|
||
|
BOOL bStatus;
|
||
|
HRESULT hr;
|
||
|
const TCHAR szEveryOne[] = TEXT("s-1-1-0");
|
||
|
|
||
|
//derive the full path of the ini file.
|
||
|
szIniFile.LoadString (IDS_INIFILE);
|
||
|
szIniFile = szGPTPath + '\\' + szIniFile;
|
||
|
|
||
|
//create an empty section
|
||
|
lpszSection = new TCHAR [cbSize];
|
||
|
lpszSection[0] = lpszSection[1] = '\0';
|
||
|
|
||
|
|
||
|
switch (CheckIniFormat (szIniFile))
|
||
|
{
|
||
|
case S_OK:
|
||
|
//this section has already been converted
|
||
|
goto ConOldStlSec_CleanupAndQuit;
|
||
|
|
||
|
case S_FALSE:
|
||
|
break; //has the Redirect section but not the FolderStatus
|
||
|
//section, so there is processing to do.
|
||
|
case REGDB_E_KEYMISSING:
|
||
|
//this means that the function has neither the FolderStatus section
|
||
|
//nor the Redirect section, so we just create an empty FolderStatus
|
||
|
//section to make processing simpler in future.
|
||
|
//ignore any errors here because they don't really cause any harm
|
||
|
//however, make sure that the file is pre-created in unicode so that
|
||
|
//the WritePrivateProfile* functions don't puke in ANSI
|
||
|
PrecreateUnicodeIniFile ((LPCTSTR)szIniFile);
|
||
|
WritePrivateProfileSection (TEXT("FolderStatus"),
|
||
|
lpszSection,
|
||
|
(LPCTSTR) szIniFile);
|
||
|
hr = S_OK;
|
||
|
goto ConOldStlSec_CleanupAndQuit;
|
||
|
}
|
||
|
|
||
|
//this means that we need to convert the section ourselves
|
||
|
//first load the redirect section
|
||
|
do
|
||
|
{
|
||
|
cbCopied = GetPrivateProfileSection (TEXT("Redirect"),
|
||
|
lpszSection,
|
||
|
cbSize,
|
||
|
(LPCTSTR) szIniFile
|
||
|
);
|
||
|
if (cbSize - 2 == cbCopied)
|
||
|
{
|
||
|
delete [] lpszSection;
|
||
|
cbSize *= 2;
|
||
|
lpszSection = new TCHAR [cbSize];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//the section has been successfully loaded if we are here.
|
||
|
break;
|
||
|
} while (TRUE);
|
||
|
|
||
|
//start the conversion process:
|
||
|
for (szEntry = lpszSection; *szEntry; szEntry += (lstrlen(szEntry) + 1))
|
||
|
{
|
||
|
SectionEntry = szEntry;
|
||
|
if (FAILED(hr = SplitProfileString (SectionEntry, Key, Value)))
|
||
|
goto ConOldStlSec_CleanupAndQuit;
|
||
|
|
||
|
SplitRHS (Value, flags, Path);
|
||
|
Path.TrimLeft();
|
||
|
Path.TrimRight();
|
||
|
if (Path.IsEmpty())
|
||
|
Path = TEXT("%USERPROFILE%") + ('\\' + Key); //we used the relative paths for keys in the old style section
|
||
|
ExtractDisplayName (Key, Dir);
|
||
|
|
||
|
//set the new flags or modify the existing flags to reflect new behavior
|
||
|
szStartMenu.LoadString (IDS_STARTMENU);
|
||
|
szPrograms.LoadString (IDS_PROGRAMS);
|
||
|
szStartup.LoadString (IDS_STARTUP);
|
||
|
if (Dir.CompareNoCase (szStartMenu) && //it is not the start menu and
|
||
|
Dir.CompareNoCase (szPrograms) && //it is not programs and
|
||
|
Dir.CompareNoCase (szStartup)) //it is not the startup folder
|
||
|
{
|
||
|
flags |= REDIR_SETACLS; //apply acls. this was the default behavior earlier, but not any more
|
||
|
}
|
||
|
else //it is one of start menu/programs/startup
|
||
|
{
|
||
|
//move contents is not allowed for start menu and its descendants
|
||
|
flags &= ~REDIR_MOVE_CONTENTS;
|
||
|
}
|
||
|
|
||
|
if ((flags & REDIR_DONT_CARE) && (flags & REDIR_FOLLOW_PARENT))
|
||
|
{
|
||
|
//if both flags were present, this implies they are linked together
|
||
|
//in the new format, in order to express this, only follow_parent
|
||
|
//is required
|
||
|
flags &= ~REDIR_DONT_CARE;
|
||
|
}
|
||
|
|
||
|
Value.Format (TEXT("%x"), flags);
|
||
|
|
||
|
bStatus = WritePrivateProfileString (TEXT("FolderStatus"),
|
||
|
Dir,
|
||
|
Value,
|
||
|
(LPCTSTR)szIniFile
|
||
|
);
|
||
|
|
||
|
if (bStatus && (!(flags & REDIR_DONT_CARE)) && (!(flags & REDIR_FOLLOW_PARENT)))
|
||
|
bStatus = WritePrivateProfileString ((LPCTSTR) Dir,
|
||
|
szEveryOne,
|
||
|
(LPCTSTR) Path,
|
||
|
(LPCTSTR) szIniFile
|
||
|
);
|
||
|
|
||
|
if (!bStatus)
|
||
|
{
|
||
|
Status = GetLastError();
|
||
|
hr = HRESULT_FROM_WIN32 (Status);
|
||
|
goto ConOldStlSec_CleanupAndQuit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ConOldStlSec_CleanupAndQuit:
|
||
|
delete [] lpszSection;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetFolderIndex
|
||
|
//
|
||
|
// Synopsis: given the name of a folder, this function returns its index
|
||
|
// in the array of CFileInfo objects in the scope pane
|
||
|
//
|
||
|
// Arguments: [in] szName : name of the folder
|
||
|
//
|
||
|
// Returns: the index of the folder or -1 if the name is invalid
|
||
|
//
|
||
|
// History: 9/28/1998 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
LONG GetFolderIndex (const CString& szName)
|
||
|
{
|
||
|
LONG i;
|
||
|
CString szBuiltinFolder;
|
||
|
|
||
|
for (i = IDS_DIRS_START; i < IDS_DIRS_END; i++)
|
||
|
{
|
||
|
szBuiltinFolder.LoadString (i);
|
||
|
if (szName.CompareNoCase((LPCTSTR)szBuiltinFolder))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return GETINDEX (i);
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CheckIniFormat
|
||
|
//
|
||
|
// Synopsis: this function examines the sections of an ini file to see
|
||
|
// if it supports the new ini file format (that allows for
|
||
|
// scaleability)
|
||
|
//
|
||
|
// Arguments: [in] szIniFile : the full path of the ini file
|
||
|
//
|
||
|
// Returns: S_OK : if it finds the FolderStatus section
|
||
|
// S_FALSE : if it does not find the FolderStatus section but
|
||
|
// finds the Redirect section
|
||
|
// REGDB_E_KEYMISSING : if it finds neither the FolderStatus
|
||
|
// section nor the Redirect section
|
||
|
//
|
||
|
// History: 9/28/1998 RahulTh created
|
||
|
//
|
||
|
// Notes: this function exists for backward compatibility with Win2K
|
||
|
// Betas. Might be okay to get rid of this eventually.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT CheckIniFormat (LPCTSTR szIniFile)
|
||
|
{
|
||
|
DWORD cbSize = 1024;
|
||
|
DWORD cbCopied;
|
||
|
TCHAR* lpszNames;
|
||
|
TCHAR* szSectionName;
|
||
|
BOOL fHasFolderStatus = FALSE;
|
||
|
BOOL fHasRedirect = FALSE;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
lpszNames = new TCHAR [cbSize];
|
||
|
if (! lpszNames)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
*lpszNames = L'\0';
|
||
|
cbCopied = GetPrivateProfileSectionNames (lpszNames, cbSize, szIniFile);
|
||
|
|
||
|
if (cbSize - 2 == cbCopied) //the buffer was not enough.
|
||
|
{
|
||
|
delete [] lpszNames;
|
||
|
cbSize *= 2; //increase the buffer size
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
break; //if we are here, we are done.
|
||
|
|
||
|
} while (TRUE);
|
||
|
|
||
|
for (szSectionName = lpszNames;
|
||
|
*szSectionName;
|
||
|
szSectionName += (lstrlen(szSectionName) + 1))
|
||
|
{
|
||
|
if (0 == lstrcmpi(TEXT("FolderStatus"), szSectionName))
|
||
|
{
|
||
|
fHasFolderStatus = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (0 == lstrcmpi (TEXT("Redirect"), szSectionName))
|
||
|
{
|
||
|
fHasRedirect = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//cleanup dynamically allocated memory before quitting
|
||
|
delete [] lpszNames;
|
||
|
|
||
|
if (fHasFolderStatus)
|
||
|
return S_OK;
|
||
|
|
||
|
//if we are here, the file does not have the FolderStatus section
|
||
|
if (fHasRedirect)
|
||
|
return S_FALSE;
|
||
|
|
||
|
//if we are here, then the file has neither the folder status section
|
||
|
//nor the Redirect section
|
||
|
return REGDB_E_KEYMISSING;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetIntfromUnicodeString
|
||
|
//
|
||
|
// Synopsis: converts a unicode string into an integer
|
||
|
//
|
||
|
// Arguments: [in] szNum : the number represented as a unicode string
|
||
|
// [in] Base : the base in which the resultant int is desired
|
||
|
// [out] pValue : pointer to the integer representation of the
|
||
|
// number
|
||
|
//
|
||
|
// Returns: STATUS_SUCCESS if successful.
|
||
|
// or some other error code
|
||
|
//
|
||
|
// History: 9/29/1998 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
NTSTATUS GetIntFromUnicodeString (const WCHAR* szNum, ULONG Base, PULONG pValue)
|
||
|
{
|
||
|
CString StrNum;
|
||
|
UNICODE_STRING StringW;
|
||
|
size_t len;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
StrNum = szNum;
|
||
|
len = StrNum.GetLength();
|
||
|
StringW.Length = len * sizeof(WCHAR);
|
||
|
StringW.MaximumLength = sizeof(WCHAR) * (len + 1);
|
||
|
StringW.Buffer = StrNum.GetBuffer(len);
|
||
|
|
||
|
Status = RtlUnicodeStringToInteger (&StringW, Base, pValue);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetUNCPath
|
||
|
//
|
||
|
// Synopsis: this function tries to retrieve the UNC path of an item
|
||
|
// given its PIDL
|
||
|
//
|
||
|
// Arguments: [in] lpszPath : the full path to the selected file.
|
||
|
// [out] szUNC : the UNC path of the item
|
||
|
//
|
||
|
// Returns: NO_ERROR if the conversion was successful.
|
||
|
// other error codes if not...
|
||
|
//
|
||
|
// History: 10/1/1998 RahulTh created
|
||
|
// 4/12/1999 RahulTh added error code. changed params.
|
||
|
// (item id list is no longer passed in)
|
||
|
//
|
||
|
// Notes: if this function is unsuccessful, then szUNC will contain an
|
||
|
// empty string
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
DWORD GetUNCPath (LPCTSTR lpszPath, CString& szUNC)
|
||
|
{
|
||
|
TCHAR* lpszUNCName;
|
||
|
UNIVERSAL_NAME_INFO* pUNCInfo;
|
||
|
DWORD lBufferSize;
|
||
|
DWORD retVal = NO_ERROR;
|
||
|
|
||
|
szUNC.Empty(); //precautionary measures
|
||
|
|
||
|
//we have a path, now we shall try to get a UNC path
|
||
|
lpszUNCName = new TCHAR[MAX_PATH];
|
||
|
pUNCInfo = (UNIVERSAL_NAME_INFO*)lpszUNCName;
|
||
|
lBufferSize = MAX_PATH * sizeof(TCHAR);
|
||
|
retVal = WNetGetUniversalName (lpszPath,
|
||
|
UNIVERSAL_NAME_INFO_LEVEL,
|
||
|
(LPVOID)pUNCInfo,
|
||
|
&lBufferSize);
|
||
|
if (ERROR_MORE_DATA == retVal) //MAX_PATH was insufficient to hold the UNC path
|
||
|
{
|
||
|
delete [] lpszUNCName;
|
||
|
lpszUNCName = new TCHAR[lBufferSize/(sizeof(TCHAR)) + 1];
|
||
|
pUNCInfo = (UNIVERSAL_NAME_INFO*)lpszUNCName;
|
||
|
retVal = WNetGetUniversalName (lpszPath,
|
||
|
UNIVERSAL_NAME_INFO_LEVEL,
|
||
|
(LPVOID)pUNCInfo,
|
||
|
&lBufferSize);
|
||
|
}
|
||
|
|
||
|
//at this point we may or may not have a UNC path.
|
||
|
//if we do, we return that, or we return whatever we already have
|
||
|
if (NO_ERROR == retVal)
|
||
|
szUNC = pUNCInfo->lpUniversalName;
|
||
|
|
||
|
delete [] lpszUNCName;
|
||
|
|
||
|
return retVal;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: BrowseCallbackProc
|
||
|
//
|
||
|
// Synopsis: the callback function for SHBrowseForFolder
|
||
|
//
|
||
|
// Arguments: see Platform SDK
|
||
|
//
|
||
|
// Returns: see Platform SDK
|
||
|
//
|
||
|
// History: 4/9/1999 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg,
|
||
|
LPARAM lParam, LPARAM lpData
|
||
|
)
|
||
|
{
|
||
|
CString * pszData;
|
||
|
CString szStart;
|
||
|
int index;
|
||
|
LPITEMIDLIST lpidl = NULL;
|
||
|
TCHAR lpszPath [MAX_PATH];
|
||
|
|
||
|
pszData = (CString *) lpData;
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case BFFM_INITIALIZED:
|
||
|
if (pszData)
|
||
|
{
|
||
|
szStart = *pszData;
|
||
|
szStart.TrimRight();
|
||
|
szStart.TrimLeft();
|
||
|
if (! szStart.IsEmpty())
|
||
|
{
|
||
|
index = szStart.ReverseFind (L'\\');
|
||
|
if (-1 != index && index > 1)
|
||
|
szStart = szStart.Left (index);
|
||
|
SendMessage (hwnd, BFFM_SETSELECTION, TRUE,
|
||
|
(LPARAM)(LPCTSTR)szStart);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case BFFM_SELCHANGED:
|
||
|
//we need to check if we can get the full path to the selected folder.
|
||
|
//e.g. if the full path exceeds MAX_PATH, we cannot obtain the path
|
||
|
//from the item id list. if we cannot get the path, we should not
|
||
|
//enable the OK button. So, over here, as a precaution, we first
|
||
|
//disable the OK button. We will enable it only after we get the path.
|
||
|
SendMessage (hwnd, BFFM_ENABLEOK, FALSE, FALSE);
|
||
|
if (SHGetPathFromIDList((LPCITEMIDLIST)lParam, lpszPath))
|
||
|
{
|
||
|
//set the path into the data member and enable the OK button
|
||
|
if (lpData)
|
||
|
{
|
||
|
SendMessage (hwnd, BFFM_ENABLEOK, TRUE, TRUE);
|
||
|
*((CString *) lpData) = lpszPath;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: PrecreateUnicodeIniFile
|
||
|
//
|
||
|
// Synopsis: The WritePrivateProfile* functions do not write in unicode
|
||
|
// unless the file already exists in unicode format. Therefore,
|
||
|
// this function is used to precreate a unicode file so that
|
||
|
// the WritePrivateProfile* functions can preserve the unicodeness.
|
||
|
//
|
||
|
// Arguments: [in] lpszFilePath : the full path of the ini file.
|
||
|
//
|
||
|
// Returns: ERROR_SUCCESS if successful.
|
||
|
// an error code otherwise.
|
||
|
//
|
||
|
// History: 7/9/1999 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
DWORD PrecreateUnicodeIniFile (LPCTSTR lpszFilePath)
|
||
|
{
|
||
|
HANDLE hFile;
|
||
|
WIN32_FILE_ATTRIBUTE_DATA fad;
|
||
|
DWORD Status = ERROR_ALREADY_EXISTS;
|
||
|
DWORD dwWritten;
|
||
|
|
||
|
if (!GetFileAttributesEx (lpszFilePath, GetFileExInfoStandard, &fad))
|
||
|
{
|
||
|
if (ERROR_FILE_NOT_FOUND == (Status = GetLastError()))
|
||
|
{
|
||
|
hFile = CreateFile(lpszFilePath, GENERIC_WRITE, 0, NULL,
|
||
|
CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, NULL);
|
||
|
|
||
|
if (hFile != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
//add the unicode marker to the beginning of the file
|
||
|
//so that APIs know for sure that it is a unicode file.
|
||
|
WriteFile(hFile, L"\xfeff\r\n", 3 * sizeof(WCHAR),
|
||
|
&dwWritten, NULL);
|
||
|
//add some unicode characters to the file.
|
||
|
WriteFile(hFile, L" \r\n", 7 * sizeof(WCHAR),
|
||
|
&dwWritten, NULL);
|
||
|
CloseHandle(hFile);
|
||
|
Status = ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = GetLastError();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IsValidPrefix
|
||
|
//
|
||
|
// Synopsis: Given a path, this function determines if it is a valid prefix
|
||
|
//
|
||
|
// Arguments: [in] pathType : the type of the path
|
||
|
// [in] pwszPath : the supplied path
|
||
|
//
|
||
|
// Returns: TRUE: if the prefix is valid.
|
||
|
// FALSE: otherwise
|
||
|
//
|
||
|
// History: 3/14/2000 RahulTh created
|
||
|
//
|
||
|
// Notes: A valid prefix is either a non-unc path or a UNC path which
|
||
|
// has at least the server and the share component. It must also
|
||
|
// be a non-empty path.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
BOOL IsValidPrefix (UINT pathType, LPCTSTR pwszPath)
|
||
|
{
|
||
|
CString szPath;
|
||
|
const WCHAR * pwszProcessedPath;
|
||
|
|
||
|
if (! pwszPath || L'\0' == *pwszPath)
|
||
|
return FALSE;
|
||
|
|
||
|
szPath = pwszPath;
|
||
|
szPath.TrimLeft();
|
||
|
szPath.TrimRight();
|
||
|
szPath.TrimRight(L'\\');
|
||
|
pwszProcessedPath = (LPCTSTR) szPath;
|
||
|
|
||
|
if (PathIsUNC ((LPCTSTR) szPath))
|
||
|
{
|
||
|
// Make sure it has both the server and the share component
|
||
|
if (lstrlen (pwszProcessedPath) <= 2 ||
|
||
|
L'\\' != pwszProcessedPath[0] ||
|
||
|
L'\\' != pwszProcessedPath[1] ||
|
||
|
NULL == wcschr (&pwszProcessedPath[2], L'\\'))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we are here, we just need to make sure that the path does not contain
|
||
|
// any environment variables -- if it is not IDS_SPECIFIC_PATH
|
||
|
//
|
||
|
if (pathType != IDS_SPECIFIC_PATH &&
|
||
|
NULL != wcschr(pwszProcessedPath, L'%'))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// If we make it up to here, then the path is a valid prefix.
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: AlwaysShowMyPicsNode
|
||
|
//
|
||
|
// Synopsis: In WindowsXP, we now show the MyPics node in the scope pane
|
||
|
// only if My Pics does not follow My Docs. However, if required
|
||
|
// this MyPics can always be made visible by setting a reg. value
|
||
|
// under HKLM\Software\Policies\Microsoft\Windows\System called
|
||
|
// FRAlwaysShowMyPicsNode. This is a DWORD value and if set to
|
||
|
// non-zero, the MyPics node will always be displayed.
|
||
|
//
|
||
|
// Arguments: none.
|
||
|
//
|
||
|
// Returns: TRUE : if the value was found in the registry and was non-zero.
|
||
|
// FALSE : otherwise.
|
||
|
//
|
||
|
// History: 4/10/2001 RahulTh created
|
||
|
//
|
||
|
// Notes: Note: In case of errors, the default value of FALSE is returned.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
BOOL AlwaysShowMyPicsNode (void)
|
||
|
{
|
||
|
BOOL bAlwaysShowMyPics = FALSE;
|
||
|
DWORD dwValue = 0;
|
||
|
DWORD dwType = REG_DWORD;
|
||
|
DWORD dwSize = sizeof(DWORD);
|
||
|
HKEY hKey = NULL;
|
||
|
|
||
|
if (ERROR_SUCCESS != RegOpenKey (HKEY_LOCAL_MACHINE,
|
||
|
TEXT("Software\\Policies\\Microsoft\\Windows\\System"),
|
||
|
&hKey)
|
||
|
)
|
||
|
{
|
||
|
return bAlwaysShowMyPics;
|
||
|
}
|
||
|
|
||
|
if (ERROR_SUCCESS == RegQueryValueEx (hKey,
|
||
|
TEXT("FRAlwaysShowMyPicsNode"),
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
(LPBYTE)(&dwValue),
|
||
|
&dwSize)
|
||
|
)
|
||
|
{
|
||
|
if (REG_DWORD == dwType && dwValue)
|
||
|
bAlwaysShowMyPics = TRUE;
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hKey);
|
||
|
|
||
|
return bAlwaysShowMyPics;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CreateThemedPropertyPage
|
||
|
//
|
||
|
// Synopsis: Helper function to make sure that property pages put up
|
||
|
// by the snap-in are themed.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 4/20/2001 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HPROPSHEETPAGE CreateThemedPropertySheetPage(AFX_OLDPROPSHEETPAGE* psp)
|
||
|
{
|
||
|
PROPSHEETPAGE_V3 sp_v3 = {0};
|
||
|
CopyMemory (&sp_v3, psp, psp->dwSize);
|
||
|
sp_v3.dwSize = sizeof(sp_v3);
|
||
|
|
||
|
return (::CreatePropertySheetPage (&sp_v3));
|
||
|
}
|
||
|
|