675 lines
11 KiB
C++
675 lines
11 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1994-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name :
|
||
|
|
||
|
utcls.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Internet Properties base classes
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Ronald Meijer (ronaldm)
|
||
|
|
||
|
Project:
|
||
|
|
||
|
Internet Services Manager (cluster edition)
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
//
|
||
|
// Include Files
|
||
|
//
|
||
|
#include "stdafx.h"
|
||
|
#include "common.h"
|
||
|
//#include "idlg.h"
|
||
|
|
||
|
#include "mmc.h"
|
||
|
|
||
|
extern "C"
|
||
|
{
|
||
|
#include <lm.h>
|
||
|
}
|
||
|
|
||
|
#define SZ_REG_KEY_BASE _T("Software\\Microsoft\\%s")
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
IsServerLocal(
|
||
|
IN LPCTSTR lpszServer
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Check to see if the given name refers to the local machine
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LPCTSTR lpszServer : Server name
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if the given name refers to the local computer, FALSE otherwise
|
||
|
|
||
|
Note:
|
||
|
|
||
|
Doesn't work if the server is an ip address
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
||
|
DWORD dwSize = sizeof(szComputerName);
|
||
|
|
||
|
//
|
||
|
// CODEWORK(?): we're not checking for all the ip addresses
|
||
|
// on the local box or full dns names.
|
||
|
//
|
||
|
// Try GetComputerNameEx when we're building with NT5
|
||
|
// settings.
|
||
|
//
|
||
|
return (!lstrcmpi(_T("localhost"), PURE_COMPUTER_NAME(lpszServer))
|
||
|
|| !lstrcmp( _T("127.0.0.1"), PURE_COMPUTER_NAME(lpszServer)))
|
||
|
|| (GetComputerName(szComputerName, &dwSize)
|
||
|
&& !lstrcmpi(szComputerName, PURE_COMPUTER_NAME(lpszServer)));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
GetVolumeInformationSystemFlags(
|
||
|
IN LPCTSTR lpszPath,
|
||
|
OUT DWORD * pdwSystemFlags
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Get the system flags for the path in question
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LPCTSTR lpszPath : Path
|
||
|
DWORD * pdwSystemFlags : Returns system flags
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE for success, FALSE for failure.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ASSERT_WRITE_PTR(pdwSystemFlags);
|
||
|
|
||
|
TRACE("Getting system flags for %s\n", lpszPath);
|
||
|
|
||
|
DWORD dwMaxComponentLength;
|
||
|
TCHAR szRoot[MAX_PATH + 1];
|
||
|
TCHAR szFileSystem[MAX_PATH + 1];
|
||
|
|
||
|
//
|
||
|
// Generating root path
|
||
|
//
|
||
|
if (PathIsUNC(lpszPath))
|
||
|
{
|
||
|
//
|
||
|
// Root path of a UNC path is \\foo\bar\
|
||
|
//
|
||
|
ASSERT(lstrlen(lpszPath) < MAX_PATH);
|
||
|
|
||
|
int cSlashes = 0;
|
||
|
LPCTSTR lpszSrc = lpszPath;
|
||
|
LPTSTR lpszDst = szRoot;
|
||
|
|
||
|
while (cSlashes < 4 && *lpszSrc)
|
||
|
{
|
||
|
if ((*lpszDst++ = *lpszSrc++) == '\\')
|
||
|
{
|
||
|
++cSlashes;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!*lpszSrc)
|
||
|
{
|
||
|
*lpszDst++ = '\\';
|
||
|
}
|
||
|
|
||
|
*lpszDst = '\0';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
::wsprintf(szRoot, _T("%c:\\"), *lpszPath);
|
||
|
}
|
||
|
|
||
|
TRACE("Root path is %s\n", szRoot);
|
||
|
|
||
|
return ::GetVolumeInformation(
|
||
|
szRoot,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
&dwMaxComponentLength,
|
||
|
pdwSystemFlags,
|
||
|
szFileSystem,
|
||
|
sizeof(szFileSystem) / sizeof(TCHAR)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
LPCTSTR
|
||
|
GenerateRegistryKey(
|
||
|
OUT CString & strBuffer,
|
||
|
IN LPCTSTR lpszSubKey OPTIONAL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Generate a registry key name based on the current app, and a
|
||
|
provided subkey (optional)
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
CString & strBuffer : Buffer to create registry key name into.
|
||
|
LPCTSTR lpszSubKey : Subkey name or NULL
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Pointer to the registry key value
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
//
|
||
|
// Use the app name as the primary registry name
|
||
|
//
|
||
|
CString app_name;
|
||
|
app_name.LoadString(_Module.GetResourceInstance(), IDS_APP_TITLE);
|
||
|
strBuffer.Format(SZ_REG_KEY_BASE, app_name);
|
||
|
|
||
|
if (lpszSubKey)
|
||
|
{
|
||
|
strBuffer += _T("\\");
|
||
|
strBuffer += lpszSubKey;
|
||
|
}
|
||
|
|
||
|
TRACE("Registry key is %s\n", strBuffer);
|
||
|
}
|
||
|
catch(std::bad_alloc)
|
||
|
{
|
||
|
TRACEEOLID("!!!exception building regkey");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return strBuffer;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int
|
||
|
CountCharsToDoubleNull(
|
||
|
IN LPCTSTR lp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Count TCHARS up to and including the double NULL.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LPCTSTR lp : TCHAR Stream
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Number of chars up to and including the double NULL
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
int cChars = 0;
|
||
|
|
||
|
for(;;)
|
||
|
{
|
||
|
++cChars;
|
||
|
|
||
|
if (lp[0] == _T('\0') && lp[1] == _T('\0'))
|
||
|
{
|
||
|
return ++cChars;
|
||
|
}
|
||
|
|
||
|
++lp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CStringListEx::CStringListEx() : std::list<CString> ()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CStringListEx::~CStringListEx()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CStringListEx::PushBack(LPCTSTR str)
|
||
|
{
|
||
|
push_back(str);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CStringListEx::Clear()
|
||
|
{
|
||
|
clear();
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
CStringListEx::ConvertFromDoubleNullList(LPCTSTR lpstrSrc, int cChars)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Convert a double null terminate list of null terminated strings to a more
|
||
|
manageable CStringList
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LPCTSTR lpstrSrc : Source list of strings
|
||
|
int cChars : Number of characters in double NULL list. if
|
||
|
-1, autodetermine length
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ERROR_SUCCESS if the list was converted properly
|
||
|
ERROR_INVALID_PARAMETER if the list was empty
|
||
|
ERROR_NOT_ENOUGH_MEMORY if there was a mem exception
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD err = ERROR_SUCCESS;
|
||
|
|
||
|
if (lpstrSrc == NULL)
|
||
|
{
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (cChars < 0)
|
||
|
{
|
||
|
//
|
||
|
// Calculate our own size. This might be off if multiple
|
||
|
// blank linkes (0) appear in the multi_sz, so the character
|
||
|
// size is definitely preferable
|
||
|
//
|
||
|
cChars = CountCharsToDoubleNull(lpstrSrc);
|
||
|
}
|
||
|
|
||
|
try
|
||
|
{
|
||
|
clear();
|
||
|
|
||
|
if (cChars == 2 && *lpstrSrc == _T('\0'))
|
||
|
{
|
||
|
//
|
||
|
// Special case: MULTI_SZ containing only
|
||
|
// a double NULL are in fact blank entirely.
|
||
|
//
|
||
|
// N.B. IMHO this is a metabase bug -- RonaldM
|
||
|
//
|
||
|
--cChars;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Grab strings until only the final NULL remains
|
||
|
//
|
||
|
while (cChars > 1)
|
||
|
{
|
||
|
CString strTmp = lpstrSrc;
|
||
|
push_back(strTmp);
|
||
|
lpstrSrc += (strTmp.GetLength() + 1);
|
||
|
cChars -= (strTmp.GetLength() + 1);
|
||
|
}
|
||
|
}
|
||
|
catch(std::bad_alloc)
|
||
|
{
|
||
|
TRACEEOLID("!!! exception building stringlist");
|
||
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
CStringListEx::ConvertToDoubleNullList(
|
||
|
OUT DWORD & cchDest,
|
||
|
OUT LPTSTR & lpstrDest
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Flatten the string list into a double null terminated list
|
||
|
of null terminated strings.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
CStringList & strlSrc : Source string list
|
||
|
DWORD & cchDest : Size in characters of the resultant array
|
||
|
(including terminating NULLs)
|
||
|
LPTSTR & lpstrDest : Allocated flat array.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ERROR_SUCCESS if the list was converted properly
|
||
|
ERROR_INVALID_PARAMETER if the list was empty
|
||
|
ERROR_NOT_ENOUGH_MEMORY if there was a mem exception
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
cchDest = 0;
|
||
|
lpstrDest = NULL;
|
||
|
BOOL fNullPad = FALSE;
|
||
|
|
||
|
//
|
||
|
// Compute total size in characters
|
||
|
//
|
||
|
CStringListEx::iterator it = begin();
|
||
|
|
||
|
while (it != end())
|
||
|
{
|
||
|
CString & str = (*it++);
|
||
|
|
||
|
// TRACEEOLID(str);
|
||
|
|
||
|
cchDest += str.GetLength() + 1;
|
||
|
}
|
||
|
|
||
|
if (!cchDest)
|
||
|
{
|
||
|
//
|
||
|
// Special case: A totally empty MULTI_SZ
|
||
|
// in fact consists of 2 (final) NULLS, instead
|
||
|
// of 1 (final) NULL. This is required by the
|
||
|
// metabase, but should be a bug. See note
|
||
|
// at reversal function above.
|
||
|
//
|
||
|
++cchDest;
|
||
|
fNullPad = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Remember final NULL
|
||
|
//
|
||
|
cchDest += 1;
|
||
|
|
||
|
lpstrDest = new TCHAR[cchDest];
|
||
|
if (lpstrDest == NULL)
|
||
|
{
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
LPTSTR pch = lpstrDest;
|
||
|
it = begin();
|
||
|
while (it != end())
|
||
|
{
|
||
|
CString & str = (*it++);
|
||
|
|
||
|
lstrcpy(pch, (LPCTSTR)str);
|
||
|
pch += str.GetLength();
|
||
|
*pch++ = _T('\0');
|
||
|
}
|
||
|
|
||
|
*pch++ = _T('\0');
|
||
|
|
||
|
if (fNullPad)
|
||
|
{
|
||
|
*pch++ = _T('\0');
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// CBlob Implementation
|
||
|
//
|
||
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||
|
|
||
|
|
||
|
CBlob::CBlob()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
NULL constructor
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
N/A
|
||
|
|
||
|
--*/
|
||
|
: m_pbItem(NULL),
|
||
|
m_dwSize(0L)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CBlob::CBlob(
|
||
|
IN DWORD dwSize,
|
||
|
IN PBYTE pbItem,
|
||
|
IN BOOL fMakeCopy
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Constructor
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DWORD dwSize : Size of memory block
|
||
|
PBYTE pbItem : Pointer to memory block
|
||
|
BOOL fMakeCopy : If TRUE, makes a copy of the memory block.
|
||
|
If FALSE, takes ownership of the pointer.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
N/A
|
||
|
|
||
|
--*/
|
||
|
: m_pbItem(NULL),
|
||
|
m_dwSize(0L)
|
||
|
{
|
||
|
SetValue(dwSize, pbItem, fMakeCopy);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CBlob::CBlob(
|
||
|
IN const CBlob & blob
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Copy constructor
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
const CBlob & blob : Source blob
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
N/A
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
This contructor makes a copy of the memory block in question.
|
||
|
|
||
|
--*/
|
||
|
: m_pbItem(NULL),
|
||
|
m_dwSize(0L)
|
||
|
{
|
||
|
SetValue(blob.GetSize(), blob.m_pbItem, TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
CBlob::SetValue(
|
||
|
IN DWORD dwSize,
|
||
|
IN PBYTE pbItem,
|
||
|
IN BOOL fMakeCopy OPTIONAL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Assign the value to this binary object. If fMakeCopy is FALSE,
|
||
|
the blob will take ownership of the pointer, otherwise a copy
|
||
|
will be made.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DWORD dwSize : Size in bytes
|
||
|
PBYTE pbItem : Byte streadm
|
||
|
BOOL fMakeCopy : If true, make a copy, else assign pointer
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ASSERT_READ_PTR2(pbItem, dwSize);
|
||
|
|
||
|
if (!IsEmpty())
|
||
|
{
|
||
|
TRACEEOLID("Assigning value to non-empty blob. Cleaning up");
|
||
|
CleanUp();
|
||
|
}
|
||
|
|
||
|
if (dwSize > 0L)
|
||
|
{
|
||
|
//
|
||
|
// Make private copy
|
||
|
//
|
||
|
m_dwSize = dwSize;
|
||
|
|
||
|
if (fMakeCopy)
|
||
|
{
|
||
|
m_pbItem = new BYTE[m_dwSize];
|
||
|
if (NULL != m_pbItem)
|
||
|
CopyMemory(m_pbItem, pbItem, dwSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_pbItem = pbItem;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
CBlob::CleanUp()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Delete data pointer, and reset pointer and size.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if (m_pbItem)
|
||
|
{
|
||
|
delete [] m_pbItem;
|
||
|
}
|
||
|
|
||
|
m_pbItem = NULL;
|
||
|
m_dwSize = 0L;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CBlob &
|
||
|
CBlob::operator =(
|
||
|
IN const CBlob & blob
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Assign values from another CBlob.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
const CBlob & blob : Source blob
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Reference to this object
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
//
|
||
|
// Make copy of data
|
||
|
//
|
||
|
SetValue(blob.GetSize(), blob.m_pbItem, TRUE);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CBlob::operator ==(
|
||
|
IN const CBlob & blob
|
||
|
) const
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Compare two binary large objects. In order to match, the objects
|
||
|
must be the same size, and byte identical.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
const CBlob & blob : Blob to compare against.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if the objects match, FALSE otherwise.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if (GetSize() != blob.GetSize())
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return memcmp(m_pbItem, blob.m_pbItem, GetSize()) == 0;
|
||
|
}
|