mirror of https://github.com/tongzx/nt5src
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.
5043 lines
117 KiB
5043 lines
117 KiB
/*++
|
|
|
|
Copyright (c) 1994-2001 Microsoft Corporation
|
|
|
|
Module Name :
|
|
mdkeys.cpp
|
|
|
|
Abstract:
|
|
Metabase key wrapper class
|
|
|
|
Author:
|
|
Ronald Meijer (ronaldm)
|
|
Sergei Antonov (sergeia)
|
|
|
|
Project:
|
|
Internet Services Manager
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
//
|
|
// Include Files
|
|
//
|
|
#include "stdafx.h"
|
|
#include "common.h"
|
|
#include "idlg.h"
|
|
#include "mdkeys.h"
|
|
//#include <acsmb.h>
|
|
//#include <iisrf.h>
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
|
|
extern HINSTANCE hDLLInstance;
|
|
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
#define MB_TIMEOUT (15000) // Timeout in milliseconds
|
|
#define MB_INIT_BUFF_SIZE ( 256) // Initial buffer size
|
|
|
|
|
|
|
|
//
|
|
// CComAuthInfo implementation
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
/* static */
|
|
BOOL
|
|
CComAuthInfo::SplitUserNameAndDomain(
|
|
IN OUT CString & strUserName,
|
|
IN CString & strDomainName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Split the user name and domain from the given
|
|
username, which is in the format "domain\user".
|
|
|
|
Return TRUE if the user name contained a domain
|
|
FALSE if it did not
|
|
|
|
Arguments:
|
|
|
|
CString & strUserName : User name which may contain a domain name
|
|
CString & strDomainName : Output domain name ("." if local)
|
|
|
|
Return Value:
|
|
|
|
TRUE if a domain is split off
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Assume local
|
|
//
|
|
strDomainName = _T(".");
|
|
int nSlash = strUserName.Find(_T("\\"));
|
|
|
|
if (nSlash >= 0)
|
|
{
|
|
strDomainName = strUserName.Left(nSlash);
|
|
strUserName = strUserName.Mid(nSlash + 1);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
DWORD
|
|
CComAuthInfo::VerifyUserPassword(
|
|
IN LPCTSTR lpstrUserName,
|
|
IN LPCTSTR lpstrPassword
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify the usernamer password combo checks out
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpstrUserName : Domain/username combo
|
|
LPCTSTR lpstrPassword : Password
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if the password checks out, an error code
|
|
otherwise.
|
|
|
|
--*/
|
|
{
|
|
CString strDomain;
|
|
CString strUser(lpstrUserName);
|
|
CString strPassword(lpstrPassword);
|
|
|
|
SplitUserNameAndDomain(strUser, strDomain);
|
|
|
|
//
|
|
// In order to look up an account name, this process
|
|
// must first be granted the privilege of doing so.
|
|
//
|
|
CError err;
|
|
{
|
|
HANDLE hToken;
|
|
LUID AccountLookupValue;
|
|
TOKEN_PRIVILEGES tkp;
|
|
|
|
do
|
|
{
|
|
if (!::OpenProcessToken(GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&hToken)
|
|
)
|
|
{
|
|
err.GetLastWinError();
|
|
break;
|
|
}
|
|
|
|
if (!::LookupPrivilegeValue(NULL, SE_TCB_NAME, &AccountLookupValue))
|
|
{
|
|
err.GetLastWinError();
|
|
break;
|
|
}
|
|
|
|
tkp.PrivilegeCount = 1;
|
|
tkp.Privileges[0].Luid = AccountLookupValue;
|
|
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
::AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&tkp,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
(PTOKEN_PRIVILEGES)NULL,
|
|
(PDWORD)NULL
|
|
);
|
|
|
|
err.GetLastWinError();
|
|
|
|
if (err.Failed())
|
|
{
|
|
break;
|
|
}
|
|
|
|
HANDLE hUser = NULL;
|
|
|
|
if (::LogonUser(
|
|
strUser.GetBuffer(0),
|
|
strDomain.GetBuffer(0),
|
|
strPassword.GetBuffer(0),
|
|
LOGON32_LOGON_NETWORK,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&hUser
|
|
))
|
|
{
|
|
//
|
|
// Success!
|
|
//
|
|
CloseHandle(hUser);
|
|
}
|
|
else
|
|
{
|
|
err.GetLastWinError();
|
|
}
|
|
|
|
//
|
|
// Remove the privilege
|
|
//
|
|
}
|
|
while(FALSE);
|
|
}
|
|
|
|
HANDLE hUser = NULL;
|
|
|
|
if (::LogonUser(
|
|
strUser.GetBuffer(0),
|
|
strDomain.GetBuffer(0),
|
|
strPassword.GetBuffer(0),
|
|
LOGON32_LOGON_NETWORK,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&hUser))
|
|
{
|
|
//
|
|
// Success!
|
|
//
|
|
CloseHandle(hUser);
|
|
}
|
|
else
|
|
{
|
|
err.GetLastWinError();
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
CComAuthInfo::CComAuthInfo(
|
|
IN LPCOLESTR lpszServerName OPTIONAL,
|
|
IN LPCOLESTR lpszUserName OPTIONAL,
|
|
IN LPCOLESTR lpszPassword OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct CIIServer object
|
|
|
|
Argument:
|
|
|
|
LPCOLESTR lpszServerName : Server name or NULL for local computer
|
|
LPCOLESTR lpszUserName : User name of blank for no impersonation
|
|
LPCOLESTR lpszPassword : Password (might be blank or NULL)
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_bstrServerName(),
|
|
m_bstrUserName(lpszUserName),
|
|
m_bstrPassword(lpszPassword),
|
|
m_fLocal(FALSE)
|
|
{
|
|
SetComputerName(lpszServerName);
|
|
}
|
|
|
|
|
|
|
|
CComAuthInfo::CComAuthInfo(
|
|
IN CComAuthInfo & auth
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy constructor
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo & auth : Source object to copy from
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_bstrServerName(auth.m_bstrServerName),
|
|
m_bstrUserName(auth.m_bstrUserName),
|
|
m_bstrPassword(auth.m_bstrPassword),
|
|
m_fLocal(auth.m_fLocal)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
CComAuthInfo::CComAuthInfo(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy constructor
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Source object to copy from (or NULL)
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_bstrServerName(),
|
|
m_bstrUserName(),
|
|
m_bstrPassword(),
|
|
m_fLocal(FALSE)
|
|
{
|
|
if (pAuthInfo)
|
|
{
|
|
//
|
|
// Full authentication information available
|
|
//
|
|
m_bstrUserName = pAuthInfo->m_bstrUserName;
|
|
m_bstrPassword = pAuthInfo->m_bstrPassword;
|
|
m_bstrServerName = pAuthInfo->m_bstrServerName;
|
|
m_fLocal = pAuthInfo->m_fLocal;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Local computer w/o impersonation
|
|
//
|
|
SetComputerName(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CComAuthInfo &
|
|
CComAuthInfo::operator =(
|
|
IN CComAuthInfo & auth
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assignment operator
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo & auth : Source object to copy from
|
|
|
|
Return Value:
|
|
|
|
Reference to current object
|
|
|
|
--*/
|
|
{
|
|
m_bstrServerName = auth.m_bstrServerName;
|
|
m_bstrUserName = auth.m_bstrUserName;
|
|
m_bstrPassword = auth.m_bstrPassword;
|
|
m_fLocal = auth.m_fLocal;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
CComAuthInfo &
|
|
CComAuthInfo::operator =(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assignment operator
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Source object to copy from (or NULL)
|
|
|
|
Return Value:
|
|
|
|
Reference to current object
|
|
|
|
--*/
|
|
{
|
|
if (pAuthInfo)
|
|
{
|
|
m_bstrUserName = pAuthInfo->m_bstrUserName;
|
|
m_bstrPassword = pAuthInfo->m_bstrPassword;
|
|
SetComputerName(pAuthInfo->m_bstrServerName);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Local computer w/o impersonation
|
|
//
|
|
m_bstrUserName.Empty();
|
|
m_bstrPassword.Empty();
|
|
SetComputerName(NULL);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
|
|
CComAuthInfo &
|
|
CComAuthInfo::operator =(
|
|
IN LPCTSTR lpszServerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assignment operator. Assign computer name w/o impersonation
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszServerName : Source server name
|
|
|
|
Return Value:
|
|
|
|
Reference to current object
|
|
|
|
--*/
|
|
{
|
|
RemoveImpersonation();
|
|
SetComputerName(lpszServerName);
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CComAuthInfo::SetComputerName(
|
|
IN LPCOLESTR lpszServerName OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store the computer name. Determine if its local.
|
|
|
|
Arguments:
|
|
|
|
LPCOLESTR lpszServername : Server name. NULL indicates the local computer
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (lpszServerName && *lpszServerName)
|
|
{
|
|
//
|
|
// Specific computer name specified
|
|
//
|
|
m_bstrServerName = lpszServerName;
|
|
m_fLocal = ::IsServerLocal(lpszServerName);
|
|
TRACEEOLID("Computer name " << lpszServerName << " Local: " << m_fLocal);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Use local computer name
|
|
//
|
|
// CODEWORK: Cache static version of computername maybe?
|
|
//
|
|
TCHAR szLocalServer[MAX_PATH + 1];
|
|
DWORD dwSize = MAX_PATH;
|
|
|
|
VERIFY(::GetComputerName(szLocalServer, &dwSize));
|
|
m_bstrServerName = szLocalServer;
|
|
m_fLocal = TRUE;
|
|
TRACEEOLID("Using local computer name " << szLocalServer);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CComAuthInfo::SetImpersonation(
|
|
IN LPCOLESTR lpszUser,
|
|
IN LPCOLESTR lpszPassword
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set impersonation parameters
|
|
|
|
Arguments:
|
|
|
|
LPCOLESTR lpszUser : User name
|
|
LPCOLESTR lpszPassword : Password
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_bstrUserName = lpszUser;
|
|
StorePassword(lpszPassword);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CComAuthInfo::RemoveImpersonation()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove impersonation parameters
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_bstrUserName.Empty();
|
|
m_bstrPassword.Empty();
|
|
}
|
|
|
|
|
|
COSERVERINFO *
|
|
CComAuthInfo::CreateServerInfoStruct() const
|
|
{
|
|
return (CComAuthInfo::CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_CONNECT));
|
|
}
|
|
|
|
|
|
|
|
COSERVERINFO *
|
|
CComAuthInfo::CreateServerInfoStruct(DWORD dwAuthnLevel) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create the server info structure. Might return NULL for the no frills case.
|
|
|
|
Arguments:
|
|
|
|
NULL
|
|
|
|
Return Value:
|
|
|
|
A COSERVERINFO structure, or NULL if the computer is local, and no
|
|
impersonation is required.
|
|
|
|
Notes:
|
|
|
|
Caller must call FreeServerInfoStruct() to prevent memory leaks
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Be smart about the server name; optimize for local
|
|
// computer name.
|
|
//
|
|
if (m_fLocal && !UsesImpersonation())
|
|
{
|
|
//
|
|
// Special, no-frills case.
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Create the COM server info for CoCreateInstanceEx
|
|
//
|
|
COSERVERINFO * pcsiName = NULL;
|
|
|
|
do
|
|
{
|
|
pcsiName = (COSERVERINFO *)AllocMem(sizeof(COSERVERINFO));
|
|
|
|
if (!pcsiName)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pcsiName->pwszName = m_bstrServerName;
|
|
|
|
//
|
|
// Set impersonation
|
|
//
|
|
if (UsesImpersonation())
|
|
{
|
|
COAUTHINFO * pAuthInfo = (COAUTHINFO *)AllocMem(sizeof(COAUTHINFO));
|
|
|
|
if (!pAuthInfo)
|
|
{
|
|
break;
|
|
}
|
|
|
|
COAUTHIDENTITY * pAuthIdentityData =
|
|
(COAUTHIDENTITY *)AllocMem(sizeof(COAUTHIDENTITY));
|
|
|
|
if (!pAuthIdentityData)
|
|
{
|
|
break;
|
|
}
|
|
|
|
CString strUserName(m_bstrUserName);
|
|
CString strPassword(m_bstrPassword);
|
|
CString strDomain;
|
|
|
|
//
|
|
// Break up domain\username combo
|
|
//
|
|
SplitUserNameAndDomain(strUserName, strDomain);
|
|
|
|
pAuthIdentityData->UserLength = strUserName.GetLength();
|
|
|
|
if (pAuthIdentityData->UserLength)
|
|
{
|
|
pAuthIdentityData->User = AllocString(
|
|
strUserName,
|
|
strUserName.GetLength()
|
|
);
|
|
}
|
|
|
|
pAuthIdentityData->DomainLength = strDomain.GetLength();
|
|
|
|
if (pAuthIdentityData->DomainLength)
|
|
{
|
|
pAuthIdentityData->Domain = AllocString(
|
|
strDomain,
|
|
strDomain.GetLength()
|
|
);
|
|
}
|
|
|
|
pAuthIdentityData->PasswordLength = strPassword.GetLength();
|
|
|
|
if (pAuthIdentityData->PasswordLength)
|
|
{
|
|
pAuthIdentityData->Password = AllocString(
|
|
strPassword,
|
|
strPassword.GetLength()
|
|
);
|
|
}
|
|
|
|
// RPC_C_AUTHN_LEVEL_DEFAULT 0
|
|
// RPC_C_AUTHN_LEVEL_NONE 1
|
|
// RPC_C_AUTHN_LEVEL_CONNECT 2
|
|
// RPC_C_AUTHN_LEVEL_CALL 3
|
|
// RPC_C_AUTHN_LEVEL_PKT 4
|
|
// RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
|
|
// RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
|
|
// you can only specify stuff stronger than RPC_C_AUTHN_LEVEL_CONNECT
|
|
if (dwAuthnLevel >= RPC_C_AUTHN_LEVEL_CONNECT && dwAuthnLevel <= RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
{
|
|
pAuthInfo->dwAuthnLevel = dwAuthnLevel;
|
|
}
|
|
else
|
|
{
|
|
pAuthInfo->dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
|
|
}
|
|
pAuthIdentityData->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
|
pAuthInfo->dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
|
|
pAuthInfo->dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
pAuthInfo->dwAuthzSvc = RPC_C_AUTHZ_NONE;
|
|
pAuthInfo->pwszServerPrincName = NULL;
|
|
pAuthInfo->dwCapabilities = EOAC_NONE;
|
|
pAuthInfo->pAuthIdentityData = pAuthIdentityData;
|
|
pcsiName->pAuthInfo = pAuthInfo;
|
|
}
|
|
}
|
|
while(FALSE);
|
|
|
|
return pcsiName;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CComAuthInfo::FreeServerInfoStruct(
|
|
IN COSERVERINFO * pServerInfo
|
|
) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
As mentioned above -- free the server info structure
|
|
|
|
Arguments:
|
|
|
|
COSERVERINFO * pServerInfo : Server info structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (pServerInfo)
|
|
{
|
|
if (pServerInfo->pAuthInfo)
|
|
{
|
|
if (pServerInfo->pAuthInfo->pAuthIdentityData)
|
|
{
|
|
if (pServerInfo->pAuthInfo->pAuthIdentityData)
|
|
{
|
|
SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->User);
|
|
SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->Domain);
|
|
SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->Password);
|
|
FreeMem(pServerInfo->pAuthInfo->pAuthIdentityData);
|
|
}
|
|
}
|
|
|
|
FreeMem(pServerInfo->pAuthInfo);
|
|
}
|
|
|
|
FreeMem(pServerInfo);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CComAuthInfo::ApplyProxyBlanket(
|
|
IN OUT IUnknown * pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set security information on the interface. The user name is of the form
|
|
domain\username.
|
|
|
|
Arguments:
|
|
|
|
IUnknown * pInterface : Interface
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
COSERVERINFO * pcsiName = CreateServerInfoStruct();
|
|
|
|
//
|
|
// This method should only be called if we're using impersonation.
|
|
// so the pcsiName returned should never be NULL.
|
|
//
|
|
ASSERT(pcsiName && pcsiName->pAuthInfo);
|
|
|
|
if (pcsiName && pcsiName->pAuthInfo)
|
|
{
|
|
hr = ::CoSetProxyBlanket(
|
|
pInterface,
|
|
pcsiName->pAuthInfo->dwAuthnSvc,
|
|
pcsiName->pAuthInfo->dwAuthzSvc,
|
|
pcsiName->pAuthInfo->pwszServerPrincName,
|
|
pcsiName->pAuthInfo->dwAuthnLevel,
|
|
pcsiName->pAuthInfo->dwImpersonationLevel,
|
|
pcsiName->pAuthInfo->pAuthIdentityData,
|
|
pcsiName->pAuthInfo->dwCapabilities
|
|
);
|
|
|
|
FreeServerInfoStruct(pcsiName);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CMetabasePath implemention
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
const LPCTSTR CMetabasePath::_cszMachine = SZ_MBN_MACHINE;
|
|
const LPCTSTR CMetabasePath::_cszRoot = SZ_MBN_ROOT;
|
|
const LPCTSTR CMetabasePath::_cszSep = SZ_MBN_SEP_STR;
|
|
const TCHAR CMetabasePath::_chSep = SZ_MBN_SEP_CHAR;
|
|
|
|
|
|
|
|
/* static */
|
|
LPCTSTR
|
|
CMetabasePath::ConvertToParentPath(
|
|
OUT IN CString & strMetaPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given the path, convert it to the parent path
|
|
e.g. "foo/bar/etc" returns "foo/bar"
|
|
|
|
Arguments:
|
|
|
|
CString & strMetaPath : Path to be converted
|
|
|
|
Return value:
|
|
|
|
Pointer to the converted path, or NULL in case of error
|
|
|
|
--*/
|
|
{
|
|
TRACEEOLID("Getting parent path of " << strMetaPath);
|
|
|
|
LPTSTR lpszPath = strMetaPath.GetBuffer(1);
|
|
LPTSTR lpszTail = lpszPath + lstrlen(lpszPath) - 1;
|
|
LPTSTR lpszReturn = NULL;
|
|
|
|
do
|
|
{
|
|
if (lpszTail <= lpszPath)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Strip trailing backslash
|
|
//
|
|
if (*lpszTail == _chSep)
|
|
{
|
|
*lpszTail-- = _T('\0');
|
|
}
|
|
|
|
//
|
|
// Search for parent
|
|
//
|
|
while (lpszTail > lpszPath && *lpszTail != _chSep)
|
|
{
|
|
--lpszTail;
|
|
}
|
|
|
|
if (lpszTail <= lpszPath)
|
|
{
|
|
break;
|
|
}
|
|
|
|
*lpszTail = _T('\0');
|
|
|
|
lpszReturn = lpszPath;
|
|
}
|
|
while(FALSE);
|
|
|
|
strMetaPath.ReleaseBuffer();
|
|
|
|
TRACEEOLID("Parent path should be " << strMetaPath);
|
|
|
|
return lpszReturn;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
LPCTSTR
|
|
CMetabasePath::TruncatePath(
|
|
IN int nLevel,
|
|
IN LPCTSTR lpszMDPath,
|
|
OUT CString & strNewPath,
|
|
OUT CString * pstrRemainder OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Truncate the given metabase path at the given level, that is,
|
|
the nLevel'th separator in the path, starting at 0, where 0 will
|
|
always give lpszPath back whether it started with a separator or not.
|
|
|
|
Examples:
|
|
|
|
"/lm/w3svc/1/foo" at level 2 returns "/lm/w3svc" as does
|
|
"lm/w3svc/1/foo".
|
|
|
|
Arguments:
|
|
|
|
int nLevel 0-based separator count to truncate at.
|
|
LPTSTR lpszMDPath Fully-qualified metabase path
|
|
CString & strNewPath Returns truncated path
|
|
CString * pstrRemainder Optionally returns the remainder past
|
|
the nLevel'th separator.
|
|
|
|
Return Value:
|
|
|
|
The truncated path at the level requested. See examples above. *pstrRemainder
|
|
returns the remainder of the path. If the path does not contain nLevel
|
|
worth of separators, the entire path is returned, and the remainder will be
|
|
blank.
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PTR(lpszMDPath);
|
|
ASSERT(nLevel >= 0);
|
|
|
|
if (!lpszMDPath || nLevel < 0)
|
|
{
|
|
TRACEEOLID("TruncatePath: Invalid parameter");
|
|
return NULL;
|
|
}
|
|
|
|
TRACEEOLID("Source Path: " << lpszMDPath);
|
|
|
|
//
|
|
// Skip the first sep whether it exists or not
|
|
//
|
|
LPCTSTR lp = *lpszMDPath == _chSep ? lpszMDPath + 1 : lpszMDPath;
|
|
LPCTSTR lpRem = NULL;
|
|
int cSeparators = 0;
|
|
|
|
if (nLevel)
|
|
{
|
|
//
|
|
// Advance to the requested separator level
|
|
//
|
|
while (*lp)
|
|
{
|
|
if (*lp == _chSep)
|
|
{
|
|
if (++cSeparators == nLevel)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
++lp;
|
|
}
|
|
|
|
if (!*lp)
|
|
{
|
|
//
|
|
// End of path is considered a separator
|
|
//
|
|
++cSeparators;
|
|
}
|
|
|
|
ASSERT(cSeparators <= nLevel);
|
|
|
|
if (cSeparators == nLevel)
|
|
{
|
|
//
|
|
// Break up the strings
|
|
//
|
|
strNewPath = lpszMDPath;
|
|
strNewPath.ReleaseBuffer((int)(lp - lpszMDPath));
|
|
|
|
TRACEEOLID("Path truncated at level " << nLevel << ": " << strNewPath);
|
|
|
|
if (*lp)
|
|
{
|
|
lpRem = ++lp;
|
|
TRACEEOLID("Remainder: " << lpRem);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return remainder
|
|
//
|
|
if (pstrRemainder && lpRem)
|
|
{
|
|
ASSERT_WRITE_PTR(pstrRemainder);
|
|
*pstrRemainder = lpRem;
|
|
}
|
|
|
|
return strNewPath;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
DWORD
|
|
CMetabasePath::GetInstanceNumber(
|
|
IN LPCTSTR lpszMDPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the number of the instance referred to in the given metabase
|
|
path.
|
|
|
|
Examples: "lm/w3svc/1/foo/bar" will return 1
|
|
"lm/w3svc/" will return 0 (master instance)
|
|
"lm/bogus/path/" will return 0xffffffff (error)
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszMDPath : A metabase path.
|
|
|
|
Return Value:
|
|
|
|
Instance number (0 indicates master instance)
|
|
or 0xffffffff if the path is in error.
|
|
|
|
--*/
|
|
{
|
|
TRACEEOLID("Determining instance number of " << lpszMDPath);
|
|
DWORD dwInstance = 0xffffffff;
|
|
|
|
CString strService, strInst;
|
|
|
|
if (GetServicePath(lpszMDPath, strService, &strInst))
|
|
{
|
|
if (strInst.IsEmpty())
|
|
{
|
|
dwInstance = MASTER_INSTANCE;
|
|
}
|
|
else
|
|
{
|
|
if (_istdigit(strInst.GetAt(0)))
|
|
{
|
|
dwInstance = _ttol(strInst);
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwInstance;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
LPCTSTR
|
|
CMetabasePath::GetLastNodeName(
|
|
IN LPCTSTR lpszMDPath,
|
|
OUT CString & strNodeName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the last nodename off the metabase path
|
|
|
|
Example:
|
|
|
|
"/lm/foo/bar/" returns "bar"
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszMDPath : Metabase path
|
|
|
|
Return Value:
|
|
|
|
Pointer to the node name or NULL in case of a malformed path.
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PTR(lpszMDPath);
|
|
|
|
if (!lpszMDPath || !*lpszMDPath)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
TRACEEOLID("Getting last node name from " << lpszMDPath);
|
|
|
|
LPCTSTR lp;
|
|
LPCTSTR lpTail;
|
|
lp = lpTail = lpszMDPath + lstrlen(lpszMDPath) - 1;
|
|
|
|
//
|
|
// Skip trailing separator
|
|
//
|
|
if (*lp == _chSep)
|
|
{
|
|
--lpTail;
|
|
--lp;
|
|
}
|
|
|
|
strNodeName.Empty();
|
|
|
|
while (*lp && *lp != _chSep)
|
|
{
|
|
strNodeName += *(lp--);
|
|
}
|
|
|
|
strNodeName.MakeReverse();
|
|
|
|
TRACEEOLID("Node is " << strNodeName);
|
|
|
|
return strNodeName;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
void
|
|
CMetabasePath::SplitMetaPathAtInstance(
|
|
IN LPCTSTR lpszMDPath,
|
|
OUT CString & strParent,
|
|
OUT CString & strAlias
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Split the given path into parent metabase root and alias, with the root
|
|
being the instance path, and the alias everything following the
|
|
instance.
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszMDPath : Input path
|
|
CString & strParent : Outputs the parent path
|
|
CString & strAlias : Outputs the alias name
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PTR(lpszMDPath);
|
|
|
|
TRACEEOLID("Source Path " << lpszMDPath);
|
|
|
|
strParent = lpszMDPath;
|
|
strAlias.Empty();
|
|
|
|
LPTSTR lp = strParent.GetBuffer(0);
|
|
ASSERT_PTR(lp);
|
|
|
|
if (!lp)
|
|
{
|
|
//
|
|
// This is just about impossible
|
|
//
|
|
return;
|
|
}
|
|
|
|
int cSeparators = 0;
|
|
int iChar = 0;
|
|
|
|
//
|
|
// Looking for "LM/sss/ddd/" <-- 3d slash:
|
|
//
|
|
while (*lp && cSeparators < 2)
|
|
{
|
|
if (*lp++ == _chSep)
|
|
{
|
|
++cSeparators;
|
|
}
|
|
|
|
++iChar;
|
|
}
|
|
|
|
if (!*lp)
|
|
{
|
|
//
|
|
// Bogus format
|
|
//
|
|
ASSERT_MSG("Bogus Format");
|
|
return;
|
|
}
|
|
|
|
if (_istdigit(*lp))
|
|
{
|
|
//
|
|
// Not at the master instance, skip one more.
|
|
//
|
|
while (*lp)
|
|
{
|
|
++iChar;
|
|
|
|
if (*lp++ == _chSep)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!*lp)
|
|
{
|
|
//
|
|
// Bogus format
|
|
//
|
|
ASSERT_MSG("Bogus Format");
|
|
return;
|
|
}
|
|
}
|
|
|
|
strAlias = strParent.Mid(iChar);
|
|
strParent.ReleaseBuffer(--iChar);
|
|
|
|
TRACEEOLID("Broken up into " << strParent);
|
|
TRACEEOLID(" and " << strAlias);
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
BOOL
|
|
CMetabasePath::IsHomeDirectoryPath(
|
|
IN LPCTSTR lpszMetaPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if the path given describes a root directory
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszMetaPath : Metabase path
|
|
|
|
Return Value:
|
|
|
|
TRUE if the path describes a root directory,
|
|
FALSE if it does not
|
|
|
|
--*/
|
|
{
|
|
ASSERT_READ_PTR(lpszMetaPath);
|
|
|
|
LPTSTR lpNode = lpszMetaPath ? _tcsrchr(lpszMetaPath, _chSep) : NULL;
|
|
|
|
if (lpNode)
|
|
{
|
|
return _tcsicmp(++lpNode, _cszRoot) == 0;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
BOOL
|
|
CMetabasePath::IsMasterInstance(
|
|
IN LPCTSTR lpszMDPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if the given metabase path points to the master instance
|
|
(site). This is essentially the service path.
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszMDPath : Metabase path.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the path is the master instance,
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
ASSERT_READ_PTR(lpszMDPath);
|
|
|
|
if (!lpszMDPath || !*lpszMDPath)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
TRACEEOLID("Checking path " << lpszMDPath);
|
|
|
|
CString strService;
|
|
CString strRemainder;
|
|
|
|
LPCTSTR lpPath = TruncatePath(2, lpszMDPath, strService, &strRemainder);
|
|
|
|
return lpPath && !strService.IsEmpty() && strRemainder.IsEmpty();
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
LPCTSTR
|
|
CMetabasePath::GetServiceInfoPath(
|
|
IN LPCTSTR lpszMDPath,
|
|
OUT CString & strInfoPath,
|
|
IN LPCTSTR lpszDefService OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate the appropriate metabase service info path for the given
|
|
metabase path.
|
|
|
|
For example:
|
|
|
|
"lm/w3svc/1/foo/bar" Generates "lm/w3svc/info"
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszMDPath : Input metabase path
|
|
CString & strInfoPath : Returns the info path
|
|
LPCTSTR lpszDefService : Optionally specifies the default service to
|
|
use (e.g "w3svc") if no service could be found
|
|
in the path.
|
|
|
|
Return Value:
|
|
|
|
The info metabase path or NULL if one could not be generated.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Capability info stored off the service path ("lm/w3svc").
|
|
//
|
|
CString strService;
|
|
CString strRem;
|
|
|
|
//
|
|
// Strip off everything past the service
|
|
//
|
|
if (!TruncatePath(2, lpszMDPath, strService, &strRem)
|
|
|| strService.IsEmpty())
|
|
{
|
|
if (!lpszDefService)
|
|
{
|
|
TRACEEOLID("Unable to generate info path");
|
|
return NULL;
|
|
}
|
|
|
|
TRACEEOLID("Using default service for info path");
|
|
|
|
//
|
|
// Machine path (no service). Use web as default service to
|
|
// look for capability and version info.
|
|
//
|
|
strService = CMetabasePath(TRUE, lpszDefService);
|
|
}
|
|
|
|
strInfoPath = CMetabasePath(FALSE, strService, SZ_MBN_INFO);
|
|
TRACEEOLID("Using " << strInfoPath << " to look for capability info");
|
|
|
|
return strInfoPath;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
LPCTSTR
|
|
CMetabasePath::CleanMetaPath(
|
|
IN OUT CString & strMetaRoot
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clean up the metabase path to one valid for internal consumption.
|
|
This removes the beginning and trailing slashes off the path.
|
|
|
|
Arguments:
|
|
|
|
CString & strMetaRoot : Metabase path to be cleaned up.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the metabase path
|
|
|
|
--*/
|
|
{
|
|
TRACEEOLID("Dirty metapath: " << strMetaRoot);
|
|
|
|
if (!strMetaRoot.IsEmpty())
|
|
{
|
|
if (strMetaRoot[strMetaRoot.GetLength() - 1] == _chSep)
|
|
{
|
|
strMetaRoot.ReleaseBuffer(strMetaRoot.GetLength() - 1);
|
|
}
|
|
|
|
if (!strMetaRoot.IsEmpty() && strMetaRoot[0] == _chSep)
|
|
{
|
|
strMetaRoot = strMetaRoot.Right(strMetaRoot.GetLength() - 1);
|
|
}
|
|
}
|
|
|
|
TRACEEOLID("Clean metapath: " << strMetaRoot);
|
|
|
|
return strMetaRoot;
|
|
}
|
|
|
|
|
|
|
|
CMetabasePath::CMetabasePath(
|
|
IN BOOL fAddBasePath,
|
|
IN LPCTSTR lpszMDPath,
|
|
IN LPCTSTR lpszMDPath2 OPTIONAL,
|
|
IN LPCTSTR lpszMDPath3 OPTIONAL,
|
|
IN LPCTSTR lpszMDPath4 OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor.
|
|
|
|
Arguments:
|
|
|
|
BOOL fAddBasePath : TRUE to prepend base path ("LM")
|
|
FALSE if the path is complete
|
|
LPCTSTR lpszMDPath : Metabase path
|
|
LPCTSTR lpszMDPath2 : Optional child path
|
|
LPCTSTR lpszMDPath3 : Optional child path
|
|
LPCTSTR lpszMDPath4 : Optional child path
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_strMetaPath()
|
|
{
|
|
ASSERT_READ_PTR(lpszMDPath);
|
|
|
|
if (fAddBasePath)
|
|
{
|
|
m_strMetaPath = _cszMachine;
|
|
AppendPath(lpszMDPath);
|
|
}
|
|
else
|
|
{
|
|
m_strMetaPath = lpszMDPath;
|
|
}
|
|
|
|
//
|
|
// Add optional path components
|
|
//
|
|
AppendPath(lpszMDPath2);
|
|
AppendPath(lpszMDPath3);
|
|
AppendPath(lpszMDPath4);
|
|
}
|
|
|
|
|
|
|
|
CMetabasePath::CMetabasePath(
|
|
IN LPCTSTR lpszSvc, OPTIONAL
|
|
IN DWORD dwInstance, OPTIONAL
|
|
IN LPCTSTR lpszParentPath, OPTIONAL
|
|
IN LPCTSTR lpszAlias OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor. Construct with path components.
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszSvc : Service (may be NULL or "")
|
|
DWORD dwInstance : Instance number (may be 0 for master)
|
|
LPCTSTR lpszParentPath : Parent path (may be NULL or "")
|
|
LPCTSTR lpszAlias : Alias (may be NULL or "")
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_strMetaPath()
|
|
{
|
|
BuildMetaPath(lpszSvc, dwInstance, lpszParentPath, lpszAlias);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CMetabasePath::AppendPath(
|
|
IN LPCTSTR lpszPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Append path to current metabase path
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszPath : Metabase path
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (lpszPath && *lpszPath)
|
|
{
|
|
m_strMetaPath += _cszSep;
|
|
m_strMetaPath += lpszPath;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CMetabasePath::AppendPath(
|
|
IN DWORD dwInstance
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Append path to current metabase path
|
|
|
|
Arguments:
|
|
|
|
DWORD dwInstance : Instance path
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (!IS_MASTER_INSTANCE(dwInstance))
|
|
{
|
|
TCHAR szInstance[] = _T("4000000000");
|
|
_ltot(dwInstance, szInstance, 10);
|
|
|
|
m_strMetaPath += _cszSep;
|
|
m_strMetaPath += szInstance;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CMetabasePath::BuildMetaPath(
|
|
IN LPCTSTR lpszSvc OPTIONAL,
|
|
IN LPCTSTR lpszInstance OPTIONAL,
|
|
IN LPCTSTR lpszParentPath OPTIONAL,
|
|
IN LPCTSTR lpszAlias OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a complete metapath with the given service name, instance
|
|
number and optional path components.
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszSvc : Service (may be NULL or "")
|
|
LPCTSTR lpszInstance : Instance (may be NULL or "")
|
|
LPCTSTR lpszParentPath : Parent path (may be NULL or "")
|
|
LPCTSTR lpszAlias : Alias (may be NULL or "")
|
|
|
|
Return Value:
|
|
|
|
Pointer to internal buffer containing the path.
|
|
|
|
--*/
|
|
{
|
|
m_strMetaPath = _cszMachine;
|
|
|
|
AppendPath(lpszSvc);
|
|
AppendPath(lpszInstance);
|
|
AppendPath(lpszParentPath);
|
|
|
|
if (lpszAlias && *lpszAlias)
|
|
{
|
|
//
|
|
// Special case: If the alias is root, but we're
|
|
// at the master instance, ignore this.
|
|
//
|
|
if (lpszInstance || ::lstrcmpi(_cszRoot, lpszAlias))
|
|
{
|
|
m_strMetaPath += _cszSep;
|
|
m_strMetaPath += lpszAlias;
|
|
}
|
|
}
|
|
|
|
TRACEEOLID("Generated metapath: " << m_strMetaPath );
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
CMetabasePath::BuildMetaPath(
|
|
IN LPCTSTR lpszSvc OPTIONAL,
|
|
IN DWORD dwInstance OPTIONAL,
|
|
IN LPCTSTR lpszParentPath OPTIONAL,
|
|
IN LPCTSTR lpszAlias OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a complete metapath with the given service name, instance
|
|
number and optional path components.
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszSvc : Service (may be NULL or "")
|
|
DWORD dwInstance : Instance number (may be 0 for master)
|
|
LPCTSTR lpszParentPath : Parent path (may be NULL or "")
|
|
LPCTSTR lpszAlias : Alias (may be NULL or "")
|
|
|
|
Return Value:
|
|
|
|
Pointer to internal buffer containing the path.
|
|
|
|
--*/
|
|
{
|
|
m_strMetaPath = _cszMachine;
|
|
|
|
AppendPath(lpszSvc);
|
|
AppendPath(dwInstance);
|
|
AppendPath(lpszParentPath);
|
|
|
|
if (lpszAlias && *lpszAlias)
|
|
{
|
|
//
|
|
// Special case: If the alias is root, but we're
|
|
// at the master instance, ignore this.
|
|
//
|
|
if (!IS_MASTER_INSTANCE(dwInstance) || ::lstrcmpi(_cszRoot, lpszAlias))
|
|
{
|
|
m_strMetaPath += _cszSep;
|
|
m_strMetaPath += lpszAlias;
|
|
}
|
|
}
|
|
|
|
TRACEEOLID("Generated metapath: " << m_strMetaPath );
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// CIISInterface class
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
CIISInterface::CIISInterface(
|
|
IN CComAuthInfo * pAuthInfo, OPTIONAL
|
|
IN HRESULT hrInterface OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Base class constructor.
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Auth info or NULL for local computer
|
|
HRESULT hrInterface : Initial error code. S_OK by default.
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_auth(pAuthInfo),
|
|
m_hrInterface(hrInterface)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISInterface::Create(
|
|
IN int cInterfaces,
|
|
IN const IID rgIID[],
|
|
IN const GUID rgCLSID[],
|
|
OUT int * pnInterface, OPTIONAL
|
|
OUT IUnknown ** ppInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create interface. This will try a range of interfaces in order of priority.
|
|
|
|
Arguments:
|
|
|
|
int cInterfaces : Number of interfaces in array.
|
|
const IID * rgIID : Array if IIDs
|
|
const GUID * rgCLSID : Array of CLSIDs
|
|
int * pnInterface : Returns the interface index that was successful.
|
|
or NULL if not interested.
|
|
IUnknown ** ppInterface : Returns pointer to the interface.
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
Notes:
|
|
|
|
This will attempt to create an interface, in order of declaration in
|
|
the IID and CLSIS arrays. The first successful interface to be created
|
|
will have its index returned in *pnInterfaces.
|
|
|
|
--*/
|
|
{
|
|
ASSERT(cInterfaces > 0);
|
|
ASSERT(rgIID && rgCLSID && ppInterface);
|
|
|
|
COSERVERINFO * pcsiName = m_auth.CreateServerInfoStruct();
|
|
|
|
MULTI_QI rgmqResults;
|
|
CError err;
|
|
int nInterface;
|
|
|
|
ZeroMemory(&rgmqResults, sizeof(rgmqResults));
|
|
//
|
|
// Try to create the interface in order
|
|
//
|
|
for (nInterface = 0; nInterface < cInterfaces; ++nInterface)
|
|
{
|
|
rgmqResults.pIID = &rgIID[nInterface];
|
|
|
|
TRACEEOLID("Attempting to create interface #" << nInterface);
|
|
err = ::CoCreateInstanceEx(
|
|
rgCLSID[nInterface],
|
|
NULL,
|
|
CLSCTX_SERVER,
|
|
pcsiName,
|
|
1,
|
|
&rgmqResults
|
|
);
|
|
|
|
if (err.Succeeded() || err.Win32Error() == ERROR_ACCESS_DENIED)
|
|
{
|
|
break;
|
|
}
|
|
ZeroMemory(&rgmqResults, sizeof(rgmqResults));
|
|
}
|
|
|
|
if(err.Succeeded())
|
|
{
|
|
//
|
|
// Save the interface pointer
|
|
//
|
|
ASSERT_PTR(rgmqResults.pItf);
|
|
*ppInterface = rgmqResults.pItf;
|
|
|
|
if (pnInterface)
|
|
{
|
|
//
|
|
// Store successful interface index
|
|
//
|
|
*pnInterface = nInterface;
|
|
}
|
|
|
|
//
|
|
// Strangely enough, I now have still have to apply
|
|
// the proxy blanket. Apparently this is by design.
|
|
//
|
|
if (m_auth.UsesImpersonation())
|
|
{
|
|
ApplyProxyBlanket();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
m_auth.FreeServerInfoStruct(pcsiName);
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CMetaInterface class
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
CMetaInterface::CMetaInterface(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct and initialize the interface
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Authentication info. NULL indicates
|
|
the local computer.
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CIISInterface(pAuthInfo),
|
|
m_pInterface(NULL),
|
|
m_iTimeOutValue(MB_TIMEOUT)
|
|
{
|
|
//
|
|
// Initialize the interface
|
|
//
|
|
m_hrInterface = Create();
|
|
}
|
|
|
|
|
|
|
|
CMetaInterface::CMetaInterface(
|
|
IN CMetaInterface * pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct from existing interface (Copy Constructor)
|
|
|
|
Arguments:
|
|
|
|
CMetaInterface * pInterface : Existing interface
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
Notes:
|
|
|
|
Object will not take ownership of the interface,
|
|
it will merely add to the reference count, and
|
|
release it upon destruction
|
|
|
|
BUGBUG:
|
|
|
|
if pInterface is NULL, this will AV.
|
|
|
|
--*/
|
|
: CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
|
|
m_pInterface(pInterface->m_pInterface),
|
|
m_iTimeOutValue(pInterface->m_iTimeOutValue)
|
|
{
|
|
ASSERT_READ_PTR(m_pInterface);
|
|
m_pInterface->AddRef();
|
|
}
|
|
|
|
|
|
|
|
CMetaInterface::~CMetaInterface()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor -- releases the interface
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
SAFE_RELEASE(m_pInterface);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CMetaKey class
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
//
|
|
// Helper macros
|
|
//
|
|
#define ASSURE_PROPER_INTERFACE()\
|
|
if (!HasInterface()) { ASSERT_MSG("No interface"); return MD_ERROR_NOT_INITIALIZED; }
|
|
|
|
#define ASSURE_OPEN_KEY()\
|
|
if (!m_hKey && !m_fAllowRootOperations) { ASSERT_MSG("No open key"); return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE); }
|
|
|
|
#define FETCH_PROPERTY_DATA_OR_FAIL(dwID, md)\
|
|
ZeroMemory(&md, sizeof(md)); \
|
|
if (!GetMDFieldDef(dwID, md.dwMDIdentifier, md.dwMDAttributes, md.dwMDUserType, md.dwMDDataType))\
|
|
{ ASSERT_MSG("Bad property ID"); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); }
|
|
|
|
//
|
|
// Static Initialization
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
#define MD_SERVER_PLATFORM (IIS_MD_SERVER_BASE+100 )
|
|
#define MD_SERVER_VERSION_MAJOR (IIS_MD_SERVER_BASE+101 )
|
|
#define MD_SERVER_VERSION_MINOR (IIS_MD_SERVER_BASE+102 )
|
|
#define MD_SERVER_CAPABILITIES (IIS_MD_SERVER_BASE+103 )
|
|
|
|
|
|
//
|
|
// Metabase table
|
|
//
|
|
const CMetaKey::MDFIELDDEF CMetaKey::s_rgMetaTable[] =
|
|
{
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// !!!IMPORTANT!!! This table must be sorted on dwMDIdentifier. (Will
|
|
// ASSERT if not not sorted)
|
|
//
|
|
{ MD_MAX_BANDWIDTH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_CONNECTION_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CONNECTION_TIMEOUT },
|
|
{ MD_MAX_CONNECTIONS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MAX_CONNECTIONS },
|
|
{ MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_SERVER_COMMENT },
|
|
{ MD_SERVER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_SERVER_AUTOSTART, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_SERVER_SIZE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_SIZE },
|
|
{ MD_SERVER_LISTEN_BACKLOG, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_BACKLOG },
|
|
{ MD_SERVER_LISTEN_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_TIMEOUT },
|
|
{ MD_DOWNLEVEL_ADMIN_INSTANCE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_DOWNLEVEL_ADMIN_INSTANCE },
|
|
{ MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
|
|
{ MD_WIN32_ERROR, METADATA_VOLATILE, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
|
|
{ MD_SERVER_PLATFORM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_SERVER_VERSION_MAJOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_SERVER_VERSION_MINOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_SERVER_CAPABILITIES, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
|
|
{ MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_FILTER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_FILTER_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_AUTH_CHANGE_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_AUTH_EXPIRED_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_AUTH_NOTIFY_PWD_EXP_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_ADV_NOTIFY_PWD_EXP_IN_DAYS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_ADV_CACHE_TTL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_NET_LOGON_WKS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_USE_HOST_NAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_AUTH_EXPIRED_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_AUTH_CHANGE_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_AUTH_NOTIFY_PWD_EXP_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_FRONTPAGE_WEB, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_MAPCERT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_MAPNTACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_MAPNAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_MAPENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_MAPREALM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_MAPPWD, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_ITACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_CPP_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_SERIAL_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_CPP_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_SERIAL_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_CPP_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_SERIAL_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_CPP_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_SERIAL_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_FRONTPAGE_WEB, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_APP_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_FRIENDLY_NAME },
|
|
{ MD_APP_ROOT, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_ROOT },
|
|
{ MD_APP_ISOLATED, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_MD_APP_ISOLATED },
|
|
{ MD_CPU_LIMITS_ENABLED, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMITS_ENABLED },
|
|
{ MD_CPU_RESET_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_CPU_LIMIT_LOGEVENT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_LOGEVENT },
|
|
{ MD_CPU_LIMIT_PRIORITY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PRIORITY },
|
|
{ MD_CPU_LIMIT_PROCSTOP, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PROCSTOP },
|
|
{ MD_CPU_LIMIT_PAUSE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PAUSE },
|
|
{ MD_HC_COMPRESSION_DIRECTORY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_HC_DO_DYNAMIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_HC_DO_STATIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_HC_DO_DISK_SPACE_LIMITING, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_HC_MAX_DISK_SPACE_USAGE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PATH },
|
|
{ MD_VR_USERNAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_USERNAME },
|
|
{ MD_VR_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PASSWORD },
|
|
{ MD_VR_ACL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, BINARY_METADATA, 0 },
|
|
{ MD_VR_UPDATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
|
|
{ MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOG_TYPE },
|
|
{ MD_LOGFILE_DIRECTORY, METADATA_INHERIT, IIS_MD_UT_FILE, EXPANDSZ_METADATA,IDS_MD_LOGFILE_DIRECTORY },
|
|
{ MD_LOGFILE_PERIOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_PERIOD },
|
|
{ MD_LOGFILE_TRUNCATE_SIZE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_TRUNCATE_SIZE },
|
|
{ MD_LOGSQL_DATA_SOURCES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_DATA_SOURCES },
|
|
{ MD_LOGSQL_TABLE_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_TABLE_NAME },
|
|
{ MD_LOGSQL_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_USER_NAME },
|
|
{ MD_LOGSQL_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_PASSWORD },
|
|
{ MD_LOG_PLUGIN_ORDER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_ORDER },
|
|
{ MD_LOGEXT_FIELD_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGEXT_FIELD_MASK },
|
|
{ MD_LOGFILE_LOCALTIME_ROLLOVER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGFILE_LOCALTIME_ROLLOVER },
|
|
{ MD_CPU_LOGGING_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LOGGING_MASK },
|
|
{ MD_EXIT_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_EXIT_MESSAGE },
|
|
{ MD_GREETING_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_GREETING_MESSAGE },
|
|
{ MD_MAX_CLIENTS_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_MAX_CLIENTS_MESSAGE },
|
|
{ MD_MSDOS_DIR_OUTPUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MSDOS_DIR_OUTPUT },
|
|
{ MD_ALLOW_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ALLOW_ANONYMOUS },
|
|
{ MD_ANONYMOUS_ONLY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ANONYMOUS_ONLY },
|
|
{ MD_LOG_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_ANONYMOUS },
|
|
{ MD_LOG_NONANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_NONANONYMOUS },
|
|
{ MD_BANNER_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
|
|
{ MD_SSL_PUBLIC_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_SSL_PRIVATE_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_SSL_KEY_PASSWORD, METADATA_SECURE, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
|
|
{ MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_SSL_CTL_IDENTIFIER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_SSL_CTL_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_SSL_USE_DS_MAPPER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_AUTHORIZATION },
|
|
{ MD_REALM, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_REALM },
|
|
{ MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_EXPIRES },
|
|
{ MD_HTTP_PICS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_PICS },
|
|
{ MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_CUSTOM },
|
|
{ MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DIRECTORY_BROWSING },
|
|
{ MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOAD_FILE },
|
|
{ MD_CONTENT_NEGOTIATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CONTENT_NEGOTIATION },
|
|
{ MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_CUSTOM_ERROR },
|
|
{ MD_FOOTER_DOCUMENT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_FOOTER_DOCUMENT },
|
|
{ MD_FOOTER_ENABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_FOOTER_ENABLED },
|
|
{ MD_HTTP_REDIRECT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_REDIRECT },
|
|
{ MD_DEFAULT_LOGON_DOMAIN, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOGON_DOMAIN },
|
|
{ MD_LOGON_METHOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGON_METHOD },
|
|
{ MD_SCRIPT_MAPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_SCRIPT_MAPS },
|
|
{ MD_MIME_MAP, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_MIME_MAP },
|
|
{ MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ACCESS_PERM },
|
|
{ MD_IP_SEC, METADATA_INHERIT | METADATA_REFERENCE, IIS_MD_UT_FILE, BINARY_METADATA, IDS_MD_IP_SEC },
|
|
{ MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_USER_NAME },
|
|
{ MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_PWD },
|
|
{ MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ANONYMOUS_USE_SUBAUTH },
|
|
{ MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DONT_LOG },
|
|
{ MD_ADMIN_ACL, METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE,IIS_MD_UT_SERVER, BINARY_METADATA, IDS_MD_ADMIN_ACL },
|
|
{ MD_SSI_EXEC_DISABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSI_EXEC_DISABLED },
|
|
{ MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSL_ACCESS_PERM },
|
|
{ MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_NTAUTHENTICATION_PROVIDERS },
|
|
{ MD_SCRIPT_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SCRIPT_TIMEOUT },
|
|
{ MD_CACHE_EXTENSIONS, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CACHE_EXTENSIONS },
|
|
{ MD_CREATE_PROCESS_AS_USER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROCESS_AS_USER },
|
|
{ MD_CREATE_PROC_NEW_CONSOLE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROC_NEW_CONSOLE },
|
|
{ MD_POOL_IDC_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_POOL_IDC_TIMEOUT },
|
|
{ MD_ALLOW_KEEPALIVES, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ALLOW_KEEPALIVES },
|
|
{ MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_IS_CONTENT_INDEXED },
|
|
{ MD_ISM_ACCESS_CHECK, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
|
|
{ MD_ASP_BUFFERINGON, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_BUFFERINGON },
|
|
{ MD_ASP_LOGERRORREQUESTS, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_LOGERRORREQUESTS },
|
|
{ MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTERRORSSENTTOBROWSER },
|
|
{ MD_ASP_SCRIPTERRORMESSAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTERRORMESSAGE },
|
|
{ MD_ASP_SCRIPTFILECACHESIZE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTFILECACHESIZE },
|
|
{ MD_ASP_SCRIPTENGINECACHEMAX, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTENGINECACHEMAX },
|
|
{ MD_ASP_SCRIPTTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTTIMEOUT },
|
|
{ MD_ASP_SESSIONTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SESSIONTIMEOUT },
|
|
{ MD_ASP_ENABLEPARENTPATHS, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLEPARENTPATHS },
|
|
{ MD_ASP_ALLOWSESSIONSTATE, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ALLOWSESSIONSTATE },
|
|
{ MD_ASP_SCRIPTLANGUAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTLANGUAGE },
|
|
{ MD_ASP_EXCEPTIONCATCHENABLE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_EXCEPTIONCATCHENABLE },
|
|
{ MD_ASP_ENABLESERVERDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLESERVERDEBUG },
|
|
{ MD_ASP_ENABLECLIENTDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLECLIENTDEBUG },
|
|
|
|
{ MD_WAM_USER_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_WAM_PWD, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
//
|
|
// IIS6 Application Pools
|
|
//
|
|
{ MD_APPPOOL_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT,
|
|
METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_MAX_PROCESS_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_PINGING_ENABLED, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_IDLE_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_RAPID_FAIL_PROTECTION_ENABLED,
|
|
METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_ORPHAN_PROCESSES_FOR_DEBUGGING,
|
|
METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_STARTUP_TIMELIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_SHUTDOWN_TIMELIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_PING_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_ORPHAN_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH,
|
|
METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
{ MD_APPPOOL_PERIODIC_RESTART_SCHEDULE,
|
|
METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
|
|
{ MD_APPPOOL_IDENTITY_TYPE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_CPU_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_CPU_LIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APPPOOL_PERIODIC_RESTART_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_RAPID_FAIL_PROTECTION_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_RAPID_FAIL_PROTECTION_MAX_CRASHES,
|
|
METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_APP_APPPOOL_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
|
|
// Global parameters
|
|
{ MD_MAX_GLOBAL_BANDWIDTH, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_MAX_GLOBAL_CONNECTIONS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_GLOBAL_STANDARD_APP_MODE_ENABLED,METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_GLOBAL_LOG_IN_UTF_8, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
{ MD_ROOT_ENABLE_EDIT_WHILE_RUNNING, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
|
|
};
|
|
|
|
|
|
|
|
#define NUM_ENTRIES (sizeof(CMetaKey::s_rgMetaTable) / sizeof(CMetaKey::s_rgMetaTable[0]))
|
|
|
|
|
|
|
|
/* static */
|
|
int
|
|
CMetaKey::MapMDIDToTableIndex(
|
|
IN DWORD dwID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map MD id value to table index. Return -1 if not found
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : MD id value
|
|
|
|
Return Value:
|
|
|
|
Index into the table that coresponds to the MD id value
|
|
|
|
--*/
|
|
{
|
|
#ifdef _DEBUG
|
|
|
|
{
|
|
//
|
|
// Do a quick verification that our metadata
|
|
// table is sorted correctly.
|
|
//
|
|
static BOOL fTableChecked = FALSE;
|
|
|
|
if (!fTableChecked)
|
|
{
|
|
for (int n = 1; n < NUM_ENTRIES; ++n)
|
|
{
|
|
if (s_rgMetaTable[n].dwMDIdentifier
|
|
<= s_rgMetaTable[n - 1].dwMDIdentifier)
|
|
{
|
|
TRACEEOLID("MD ID Table is out of order: Item is "
|
|
<< n
|
|
<< " "
|
|
<< s_rgMetaTable[n].dwMDIdentifier
|
|
);
|
|
ASSERT_MSG("MD ID Table out of order");
|
|
}
|
|
}
|
|
|
|
//
|
|
// But only once.
|
|
//
|
|
++fTableChecked;
|
|
}
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//
|
|
// Look up the ID in the table using a binary search
|
|
//
|
|
int nRange = NUM_ENTRIES;
|
|
int nLow = 0;
|
|
int nHigh = nRange - 1;
|
|
int nMid;
|
|
int nHalf;
|
|
|
|
while (nLow <= nHigh)
|
|
{
|
|
if (0 != (nHalf = nRange / 2))
|
|
{
|
|
nMid = nLow + (nRange & 1 ? nHalf : (nHalf - 1));
|
|
|
|
if (s_rgMetaTable[nMid].dwMDIdentifier == dwID)
|
|
{
|
|
return nMid;
|
|
}
|
|
else if (s_rgMetaTable[nMid].dwMDIdentifier > dwID)
|
|
{
|
|
nHigh = --nMid;
|
|
nRange = nRange & 1 ? nHalf : nHalf - 1;
|
|
}
|
|
else
|
|
{
|
|
nLow = ++nMid;
|
|
nRange = nHalf;
|
|
}
|
|
}
|
|
else if (nRange)
|
|
{
|
|
return s_rgMetaTable[nLow].dwMDIdentifier == dwID ? nLow : -1;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
BOOL
|
|
CMetaKey::GetMDFieldDef(
|
|
IN DWORD dwID,
|
|
OUT DWORD & dwMDIdentifier,
|
|
OUT DWORD & dwMDAttributes,
|
|
OUT DWORD & dwMDUserType,
|
|
OUT DWORD & dwMDDataType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get information about metabase property
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Meta ID
|
|
DWORD & dwMDIdentifier : Meta parms
|
|
DWORD & dwMDAttributes : Meta parms
|
|
DWORD & dwMDUserType : Meta parms
|
|
DWORD & dwMDDataType : Meta parms
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure.
|
|
|
|
--*/
|
|
{
|
|
int nID = MapMDIDToTableIndex(dwID);
|
|
|
|
if (nID == -1)
|
|
{
|
|
//
|
|
// Unrecognized meta data ID
|
|
//
|
|
ASSERT_MSG("Unrecognized meta data id");
|
|
return FALSE;
|
|
}
|
|
|
|
dwMDIdentifier = s_rgMetaTable[nID].dwMDIdentifier;
|
|
dwMDAttributes = s_rgMetaTable[nID].dwMDAttributes;
|
|
dwMDUserType = s_rgMetaTable[nID].dwMDUserType;
|
|
dwMDDataType = s_rgMetaTable[nID].dwMDDataType;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
BOOL
|
|
CMetaKey::IsPropertyInheritable(
|
|
IN DWORD dwID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check to see if the given property is inheritable
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Metabase ID
|
|
|
|
Return Value:
|
|
|
|
TRUE if the metabase ID is inheritable, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
int nID = MapMDIDToTableIndex(dwID);
|
|
|
|
if (nID == -1)
|
|
{
|
|
//
|
|
// Unrecognized meta data ID
|
|
//
|
|
ASSERT_MSG("Unrecognized meta data ID");
|
|
return FALSE;
|
|
}
|
|
|
|
return (s_rgMetaTable[nID].dwMDAttributes & METADATA_INHERIT) != 0;
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
BOOL
|
|
CMetaKey::GetPropertyDescription(
|
|
IN DWORD dwID,
|
|
OUT CString & strName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get a description for the given property
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
CString & strName : Returns friendly property name
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
{
|
|
int nID = MapMDIDToTableIndex(dwID);
|
|
|
|
if (nID == -1)
|
|
{
|
|
//
|
|
// Unrecognized meta data ID
|
|
//
|
|
ASSERT_MSG("Unrecognized meta data ID");
|
|
return FALSE;
|
|
}
|
|
|
|
UINT uID = s_rgMetaTable[nID].uStringID;
|
|
|
|
BOOL fResult = TRUE;
|
|
|
|
if (uID > 0)
|
|
{
|
|
fResult = (strName.LoadString(uID) != 0);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Don't have a friendly name -- fake it
|
|
//
|
|
CComBSTR bstrFmt;
|
|
VERIFY(bstrFmt.LoadString(hDLLInstance, IDS_INHERITANCE_NO_NAME));
|
|
|
|
strName.Format(bstrFmt, dwID);
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
|
|
|
|
CMetaKey::CMetaKey(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor that creates the interface, but does not open the key.
|
|
This is the ONLY constructor that allows operations from
|
|
METDATA_MASTER_ROOT_HANDLE (read operations obviously)
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : If NULL, opens interface on local machine
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CMetaInterface(pAuthInfo),
|
|
m_hKey(METADATA_MASTER_ROOT_HANDLE),
|
|
m_hBase(NULL),
|
|
m_hrKey(S_OK),
|
|
m_dwFlags(0L),
|
|
m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
|
|
m_strMetaPath(),
|
|
m_fAllowRootOperations(TRUE),
|
|
m_fOwnKey(TRUE)
|
|
{
|
|
m_hrKey = CMetaInterface::QueryResult();
|
|
|
|
//
|
|
// Do not open key
|
|
//
|
|
}
|
|
|
|
|
|
|
|
CMetaKey::CMetaKey(
|
|
IN CMetaInterface * pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct with pre-existing interface. Does not
|
|
open any keys
|
|
|
|
Arguments:
|
|
|
|
CMetaInterface * pInterface : Preexisting interface
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CMetaInterface(pInterface),
|
|
m_hKey(NULL),
|
|
m_hBase(NULL),
|
|
m_strMetaPath(),
|
|
m_dwFlags(0L),
|
|
m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
|
|
m_fAllowRootOperations(TRUE),
|
|
m_fOwnKey(TRUE)
|
|
{
|
|
m_hrKey = CMetaInterface::QueryResult();
|
|
}
|
|
|
|
|
|
|
|
CMetaKey::CMetaKey(
|
|
IN CComAuthInfo * pAuthInfo, OPTIONAL
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
IN DWORD dwFlags,
|
|
IN METADATA_HANDLE hkBase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fully defined constructor that opens a key
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Auth info or NULL
|
|
LPCTSTR lpszMDPath : Path or NULL
|
|
DWORD dwFlags : Open permissions
|
|
METADATA_HANDLE hkBase : Base key
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CMetaInterface(pAuthInfo),
|
|
m_hKey(NULL),
|
|
m_hBase(NULL),
|
|
m_dwFlags(0L),
|
|
m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
|
|
m_fAllowRootOperations(FALSE),
|
|
m_strMetaPath(),
|
|
m_fOwnKey(TRUE)
|
|
{
|
|
m_hrKey = CMetaInterface::QueryResult();
|
|
|
|
if (SUCCEEDED(m_hrKey))
|
|
{
|
|
m_hrKey = Open(dwFlags, lpszMDPath, hkBase);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CMetaKey::CMetaKey(
|
|
IN CMetaInterface * pInterface,
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
IN DWORD dwFlags,
|
|
IN METADATA_HANDLE hkBase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fully defined constructor that opens a key
|
|
|
|
Arguments:
|
|
|
|
CMetaInterface * pInterface : Existing interface
|
|
DWORD dwFlags : Open permissions
|
|
METADATA_HANDLE hkBase : Base key
|
|
LPCTSTR lpszMDPath : Path or NULL
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CMetaInterface(pInterface),
|
|
m_hKey(NULL),
|
|
m_hBase(NULL),
|
|
m_strMetaPath(),
|
|
m_dwFlags(0L),
|
|
m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
|
|
m_fAllowRootOperations(FALSE),
|
|
m_fOwnKey(TRUE)
|
|
{
|
|
m_hrKey = CMetaInterface::QueryResult();
|
|
|
|
if (SUCCEEDED(m_hrKey))
|
|
{
|
|
m_hrKey = Open(dwFlags, lpszMDPath, hkBase);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CMetaKey::CMetaKey(
|
|
IN BOOL fOwnKey,
|
|
IN CMetaKey * pKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy constructor.
|
|
|
|
Arguments:
|
|
|
|
BOOL fOwnKey : TRUE to take ownership of the key
|
|
const CMetaKey * pKey : Existing key
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CMetaInterface(pKey),
|
|
m_hKey(pKey->m_hKey),
|
|
m_hBase(pKey->m_hBase),
|
|
m_dwFlags(pKey->m_dwFlags),
|
|
m_cbInitialBufferSize(pKey->m_cbInitialBufferSize),
|
|
m_fAllowRootOperations(pKey->m_fAllowRootOperations),
|
|
m_hrKey(pKey->m_hrKey),
|
|
m_strMetaPath(pKey->m_strMetaPath),
|
|
m_fOwnKey(fOwnKey)
|
|
{
|
|
//
|
|
// No provisions for anything else at the moment
|
|
//
|
|
ASSERT(!m_fOwnKey);
|
|
}
|
|
|
|
|
|
|
|
CMetaKey::~CMetaKey()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor -- Close the key.
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
if (IsOpen() && m_fOwnKey)
|
|
{
|
|
Close();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
BOOL
|
|
CMetaKey::Succeeded() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if object was constructed successfully
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
{
|
|
return SUCCEEDED(m_hrKey);
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CMetaKey::QueryResult() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the construction error for this object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT from construction errors
|
|
|
|
--*/
|
|
{
|
|
return m_hrKey;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::Open(
|
|
IN DWORD dwFlags,
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
IN METADATA_HANDLE hkBase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempt to open a metabase key
|
|
|
|
Arguments:
|
|
|
|
DWORD dwFlags : Permission flags
|
|
LPCTSTR lpszMDPath : Optional path
|
|
METADATA_HANDLE hkBase : Base metabase key
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
|
|
if (m_hKey != NULL)
|
|
{
|
|
ASSERT_MSG("Attempting to open key that already has an open handle");
|
|
|
|
TRACEEOLID("Closing that key");
|
|
Close();
|
|
}
|
|
|
|
//
|
|
// Base key is stored for reopen purposes only
|
|
//
|
|
m_hBase = hkBase;
|
|
m_strMetaPath = lpszMDPath;
|
|
m_dwFlags = dwFlags;
|
|
|
|
return OpenKey(m_hBase, m_strMetaPath, m_dwFlags, &m_hKey);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::CreatePathFromFailedOpen()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If the path doesn't exist, create it. This method should be
|
|
called after an Open call failed (because it will have initialized
|
|
m_strMetaPath.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
CString strParentPath;
|
|
CString strObjectName;
|
|
CString strSavePath(m_strMetaPath);
|
|
|
|
CMetabasePath::SplitMetaPathAtInstance(
|
|
m_strMetaPath,
|
|
strParentPath,
|
|
strObjectName
|
|
);
|
|
|
|
CError err(Open(
|
|
METADATA_PERMISSION_WRITE,
|
|
strParentPath
|
|
));
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
//
|
|
// This really should never fail, because we're opening
|
|
// the path at the instance.
|
|
//
|
|
err = AddKey(strObjectName);
|
|
}
|
|
|
|
if (IsOpen())
|
|
{
|
|
Close();
|
|
}
|
|
|
|
//
|
|
// The previous open wiped out the path...
|
|
//
|
|
m_strMetaPath = strSavePath;
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::Close()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close the currently open key.
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(m_hKey != NULL);
|
|
ASSERT(m_fOwnKey);
|
|
|
|
if (m_hKey)
|
|
{
|
|
hr = CloseKey(m_hKey);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_hKey = NULL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::ConvertToParentPath(
|
|
IN BOOL fImmediate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Change the path to the parent path.
|
|
|
|
Arguments:
|
|
|
|
BOOL fImmediate : If TRUE, the immediate parent's path will be used
|
|
if FALSE, the first parent that really exists
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
ERROR_INVALID_PARAMETER if there is no valid path
|
|
|
|
--*/
|
|
{
|
|
BOOL fIsOpen = IsOpen();
|
|
|
|
if (fIsOpen)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
CError err;
|
|
|
|
FOREVER
|
|
{
|
|
if (!CMetabasePath::ConvertToParentPath(m_strMetaPath))
|
|
{
|
|
//
|
|
// There is no parent path
|
|
//
|
|
err = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
err = ReOpen();
|
|
|
|
//
|
|
// Path not found is the only valid error
|
|
// other than success.
|
|
//
|
|
if (fImmediate
|
|
|| err.Succeeded()
|
|
|| err.Win32Error() != ERROR_PATH_NOT_FOUND)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remember to reset the construction error
|
|
// which referred to the parent path.
|
|
//
|
|
m_hrKey = err;
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* protected */
|
|
HRESULT
|
|
CMetaKey::GetPropertyValue(
|
|
IN DWORD dwID,
|
|
OUT IN DWORD & dwSize, OPTIONAL
|
|
OUT IN void *& pvData, OPTIONAL
|
|
OUT IN DWORD * pdwDataType, OPTIONAL
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
OUT DWORD * pdwAttributes OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get metadata on the currently open key.
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID number
|
|
DWORD & dwSize : Buffer size (could be 0)
|
|
void *& pvData : Buffer -- will allocate if NULL
|
|
DWORD * pdwDataType : NULL or on in contains valid data types,
|
|
: on out contains actual data type
|
|
BOOL * pfInheritanceOverride : NULL or on forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path off the open key
|
|
DWORD * pdwAttributes : Optionally returns attributes
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
ERROR_INVALID_HANDLE : If the handle is not open
|
|
ERROR_INVALID_PARAMETER : If the property id is not found,
|
|
or the data type doesn't match requested type
|
|
ERROR_OUTOFMEMORY : Out of memory
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
ASSURE_OPEN_KEY();
|
|
|
|
METADATA_RECORD mdRecord;
|
|
FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
|
|
|
|
//
|
|
// If unable to find this property ID in our table, or
|
|
// if we specified a desired type, and this type doesn't
|
|
// match it, give up.
|
|
//
|
|
if (pdwDataType && *pdwDataType != ALL_METADATA
|
|
&& *pdwDataType != mdRecord.dwMDDataType)
|
|
{
|
|
ASSERT_MSG("Invalid parameter");
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// Check to see if inheritance behaviour is overridden
|
|
//
|
|
if (pfInheritanceOverride)
|
|
{
|
|
if (*pfInheritanceOverride)
|
|
{
|
|
mdRecord.dwMDAttributes |= METADATA_INHERIT;
|
|
}
|
|
else
|
|
{
|
|
mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This causes a bad parameter error on input otherwise
|
|
//
|
|
mdRecord.dwMDAttributes &= ~METADATA_REFERENCE;
|
|
|
|
//
|
|
// If we're looking for inheritable properties, the path
|
|
// doesn't have to be completely specified.
|
|
//
|
|
if (mdRecord.dwMDAttributes & METADATA_INHERIT)
|
|
{
|
|
mdRecord.dwMDAttributes |= (METADATA_PARTIAL_PATH | METADATA_ISINHERITED);
|
|
}
|
|
|
|
ASSERT(dwSize > 0 || pvData == NULL);
|
|
|
|
mdRecord.dwMDDataLen = dwSize;
|
|
mdRecord.pbMDData = (LPBYTE)pvData;
|
|
|
|
//
|
|
// If no buffer provided, allocate one.
|
|
//
|
|
HRESULT hr = S_OK;
|
|
BOOL fBufferTooSmall = FALSE;
|
|
BOOL fAllocatedMemory = FALSE;
|
|
DWORD dwInitSize = m_cbInitialBufferSize;
|
|
|
|
do
|
|
{
|
|
if(mdRecord.pbMDData == NULL)
|
|
{
|
|
mdRecord.dwMDDataLen = dwInitSize;
|
|
mdRecord.pbMDData = (LPBYTE)AllocMem(dwInitSize);
|
|
|
|
if(mdRecord.pbMDData == NULL && dwInitSize > 0)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
|
|
break;
|
|
}
|
|
|
|
++fAllocatedMemory;
|
|
}
|
|
|
|
//
|
|
// Get the data
|
|
//
|
|
DWORD dwRequiredDataLen = 0;
|
|
hr = GetData(m_hKey, lpszMDPath, &mdRecord, &dwRequiredDataLen);
|
|
|
|
//
|
|
// Re-fetch the buffer if it's too small.
|
|
//
|
|
fBufferTooSmall =
|
|
(HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) && fAllocatedMemory;
|
|
|
|
if(fBufferTooSmall)
|
|
{
|
|
//
|
|
// Delete the old buffer, and set up for a re-fetch.
|
|
//
|
|
FreeMem(mdRecord.pbMDData);
|
|
mdRecord.pbMDData = NULL;
|
|
dwInitSize = dwRequiredDataLen;
|
|
}
|
|
}
|
|
while(fBufferTooSmall);
|
|
|
|
//
|
|
// Failed
|
|
//
|
|
if(FAILED(hr) && fAllocatedMemory)
|
|
{
|
|
FreeMem(mdRecord.pbMDData);
|
|
mdRecord.pbMDData = NULL;
|
|
}
|
|
|
|
dwSize = mdRecord.dwMDDataLen;
|
|
pvData = mdRecord.pbMDData;
|
|
|
|
if (pdwDataType != NULL)
|
|
{
|
|
//
|
|
// Return actual data type
|
|
//
|
|
*pdwDataType = mdRecord.dwMDDataType;
|
|
}
|
|
|
|
if (pdwAttributes != NULL)
|
|
{
|
|
//
|
|
// Return data attributes
|
|
//
|
|
*pdwAttributes = mdRecord.dwMDAttributes;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/* protected */
|
|
HRESULT
|
|
CMetaKey::GetDataPaths(
|
|
OUT CStringListEx & strlDataPaths,
|
|
IN DWORD dwMDIdentifier,
|
|
IN DWORD dwMDDataType,
|
|
IN LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get data paths
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
ASSURE_OPEN_KEY();
|
|
|
|
//
|
|
// Start with a small buffer
|
|
//
|
|
DWORD dwMDBufferSize = 1024;
|
|
LPTSTR lpszBuffer = NULL;
|
|
CError err;
|
|
|
|
do
|
|
{
|
|
if (lpszBuffer != NULL)
|
|
{
|
|
FreeMem(lpszBuffer);
|
|
}
|
|
|
|
lpszBuffer = AllocTString(dwMDBufferSize);
|
|
|
|
if (lpszBuffer == NULL)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
err = CMetaInterface::GetDataPaths(
|
|
m_hKey,
|
|
lpszMDPath,
|
|
dwMDIdentifier,
|
|
dwMDDataType,
|
|
dwMDBufferSize,
|
|
lpszBuffer,
|
|
&dwMDBufferSize
|
|
);
|
|
}
|
|
while(err.Win32Error() == ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
|
|
{
|
|
//
|
|
// That's ok... this is some sort of physical directory
|
|
// that doesn't currently exist in the metabase, and
|
|
// which therefore doesn't have any descendants anyway.
|
|
//
|
|
ZeroMemory(lpszBuffer, dwMDBufferSize);
|
|
err.Reset();
|
|
}
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
ConvertDoubleNullListToStringList(lpszBuffer, strlDataPaths);
|
|
FreeMem(lpszBuffer);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::CheckDescendants(
|
|
IN DWORD dwID,
|
|
IN CComAuthInfo * pAuthInfo, OPTIONAL
|
|
IN LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check for descendant overrides; If there are any, bring up a dialog
|
|
that displays them, and give the user the opportunity the remove
|
|
the overrides.
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
CComAuthInfo * pAuthInfo : Server or NULL
|
|
LPCTSTR lpszMDPath : Metabase path or NULL
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
METADATA_RECORD mdRecord;
|
|
FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
|
|
|
|
if (mdRecord.dwMDAttributes & METADATA_INHERIT)
|
|
{
|
|
CStringListEx strlDataPaths;
|
|
|
|
hr = GetDataPaths(
|
|
strlDataPaths,
|
|
mdRecord.dwMDIdentifier,
|
|
mdRecord.dwMDDataType,
|
|
lpszMDPath
|
|
);
|
|
|
|
if (SUCCEEDED(hr) && !strlDataPaths.IsEmpty())
|
|
{
|
|
//
|
|
// Bring up the inheritance override dialog
|
|
//
|
|
CInheritanceDlg dlg(
|
|
dwID,
|
|
FROM_WRITE_PROPERTY,
|
|
pAuthInfo,
|
|
lpszMDPath,
|
|
strlDataPaths
|
|
);
|
|
|
|
if (!dlg.IsEmpty())
|
|
{
|
|
dlg.DoModal();
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/* protected */
|
|
HRESULT
|
|
CMetaKey::SetPropertyValue(
|
|
IN DWORD dwID,
|
|
IN DWORD dwSize,
|
|
IN void * pvData,
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set metadata on the open key. The key must have been opened with
|
|
write permission.
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
DWORD dwSize : Size of data
|
|
void * pvData : Data buffer
|
|
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path off the open key
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
ERROR_INVALID_HANDLE : If the handle is not open
|
|
ERROR_INVALID_PARAMETER : If the property id is not found,
|
|
or the buffer is NULL or of size 0
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
ASSURE_OPEN_KEY();
|
|
|
|
if (pvData == NULL && dwSize != 0)
|
|
{
|
|
ASSERT_MSG("No Data");
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
METADATA_RECORD mdRecord;
|
|
FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
|
|
|
|
if (pfInheritanceOverride)
|
|
{
|
|
if (*pfInheritanceOverride)
|
|
{
|
|
mdRecord.dwMDAttributes |= METADATA_INHERIT;
|
|
}
|
|
else
|
|
{
|
|
mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
|
|
}
|
|
}
|
|
|
|
mdRecord.dwMDDataLen = dwSize;
|
|
mdRecord.pbMDData = (LPBYTE)pvData;
|
|
|
|
return SetData(m_hKey, lpszMDPath, &mdRecord);
|
|
}
|
|
|
|
|
|
|
|
/* protected */
|
|
HRESULT
|
|
CMetaKey::GetAllData(
|
|
IN DWORD dwMDAttributes,
|
|
IN DWORD dwMDUserType,
|
|
IN DWORD dwMDDataType,
|
|
OUT DWORD * pdwMDNumEntries,
|
|
OUT DWORD * pdwMDDataLen,
|
|
OUT PBYTE * ppbMDData,
|
|
IN LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get all data off the open key. Buffer is created automatically.
|
|
|
|
Arguments:
|
|
|
|
DWORD dwMDAttributes : Attributes
|
|
DWORD dwMDUserType : User type to fetch
|
|
DWORD dwMDDataType : Data type to fetch
|
|
DWORD * pdwMDNumEntries : Returns number of entries read
|
|
DWORD * pdwMDDataLen : Returns size of data buffer
|
|
PBYTE * ppbMDData : Returns data buffer
|
|
LPCTSTR lpszMDPath : Optional data path
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
ASSURE_OPEN_KEY();
|
|
|
|
//
|
|
// Check for valid parameters
|
|
//
|
|
if(!pdwMDDataLen || !ppbMDData || !pdwMDNumEntries)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL fBufferTooSmall = FALSE;
|
|
DWORD dwMDDataSetNumber;
|
|
DWORD dwRequiredBufferSize;
|
|
DWORD dwInitSize = m_cbInitialBufferSize;
|
|
*ppbMDData = NULL;
|
|
|
|
do
|
|
{
|
|
*pdwMDDataLen = dwInitSize;
|
|
*ppbMDData = (LPBYTE)AllocMem(dwInitSize);
|
|
|
|
if (ppbMDData == NULL && dwInitSize > 0)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
|
|
break;
|
|
}
|
|
|
|
hr = CMetaInterface::GetAllData(
|
|
m_hKey,
|
|
lpszMDPath,
|
|
dwMDAttributes,
|
|
dwMDUserType,
|
|
dwMDDataType,
|
|
pdwMDNumEntries,
|
|
&dwMDDataSetNumber,
|
|
*pdwMDDataLen,
|
|
*ppbMDData,
|
|
&dwRequiredBufferSize
|
|
);
|
|
|
|
//
|
|
// Re-fetch the buffer if it's too small.
|
|
//
|
|
fBufferTooSmall = (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
if(fBufferTooSmall)
|
|
{
|
|
//
|
|
// Delete the old buffer, and set up for a re-fetch.
|
|
//
|
|
SAFE_FREEMEM(*ppbMDData);
|
|
dwInitSize = dwRequiredBufferSize;
|
|
}
|
|
}
|
|
while (fBufferTooSmall);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// No good, be sure we don't leak anything
|
|
//
|
|
SAFE_FREEMEM(*ppbMDData);
|
|
dwInitSize = 0L;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::QueryValue(
|
|
IN DWORD dwID,
|
|
IN OUT DWORD & dwValue,
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
OUT DWORD * pdwAttributes OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fetch data as a DWORD
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
DWORD & dwValue : Returns the value read in
|
|
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path off the open key
|
|
DWORD * pdwAttributes : Optionally returns attributes
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
DWORD dwSize = sizeof(dwValue);
|
|
DWORD dwDataType = DWORD_METADATA;
|
|
void * pvData = &dwValue;
|
|
|
|
return GetPropertyValue(
|
|
dwID,
|
|
dwSize,
|
|
pvData,
|
|
&dwDataType,
|
|
pfInheritanceOverride,
|
|
lpszMDPath,
|
|
pdwAttributes
|
|
);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::QueryValue(
|
|
IN DWORD dwID,
|
|
IN OUT CString & strValue,
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
OUT DWORD * pdwAttributes OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fetch data as a string
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
DWORD & strValue : Returns the value read in
|
|
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path off the open key
|
|
DWORD * pdwAttributes : Optionally returns attributes
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Get GetData allocate the buffer for us
|
|
//
|
|
DWORD dwSize = 0;
|
|
DWORD dwDataType = ALL_METADATA;
|
|
LPTSTR lpData = NULL;
|
|
|
|
HRESULT hr = GetPropertyValue(
|
|
dwID,
|
|
dwSize,
|
|
(void *&)lpData,
|
|
&dwDataType,
|
|
pfInheritanceOverride,
|
|
lpszMDPath,
|
|
pdwAttributes
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Notes: consider optional auto-expansion on EXPANDSZ_METADATA
|
|
// (see registry functions), and data type conversions for DWORD
|
|
// or MULTISZ_METADATA or BINARY_METADATA
|
|
//
|
|
if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
|
|
{
|
|
try
|
|
{
|
|
strValue = lpData;
|
|
}
|
|
catch(CMemoryException * e)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
strValue.Empty();
|
|
e->Delete();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
if (lpData)
|
|
{
|
|
FreeMem(lpData);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::QueryValue(
|
|
IN DWORD dwID,
|
|
IN OUT CComBSTR & strValue,
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
OUT DWORD * pdwAttributes OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fetch data as a string
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
DWORD & CComBSTR : Returns the value read in
|
|
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path off the open key
|
|
DWORD * pdwAttributes : Optionally returns attributes
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Get GetData allocate the buffer for us
|
|
//
|
|
DWORD dwSize = 0;
|
|
DWORD dwDataType = ALL_METADATA;
|
|
LPTSTR lpData = NULL;
|
|
|
|
HRESULT hr = GetPropertyValue(
|
|
dwID,
|
|
dwSize,
|
|
(void *&)lpData,
|
|
&dwDataType,
|
|
pfInheritanceOverride,
|
|
lpszMDPath,
|
|
pdwAttributes
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Notes: consider optional auto-expansion on EXPANDSZ_METADATA
|
|
// (see registry functions), and data type conversions for DWORD
|
|
// or MULTISZ_METADATA or BINARY_METADATA
|
|
//
|
|
if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
|
|
{
|
|
strValue = lpData;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
if (lpData)
|
|
{
|
|
FreeMem(lpData);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::QueryValue(
|
|
IN DWORD dwID,
|
|
IN OUT CStringListEx & strlValue,
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
OUT DWORD * pdwAttributes OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fetch data as a stringlist
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
DWORD & strlValue : Returns the value read in
|
|
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path off the open key
|
|
DWORD * pdwAttributes : Optionally returns attributes
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Get GetData allocate the buffer for us
|
|
//
|
|
DWORD dwSize = 0;
|
|
DWORD dwDataType = MULTISZ_METADATA;
|
|
LPTSTR lpData = NULL;
|
|
|
|
HRESULT hr = GetPropertyValue(
|
|
dwID,
|
|
dwSize,
|
|
(void *&)lpData,
|
|
&dwDataType,
|
|
pfInheritanceOverride,
|
|
lpszMDPath,
|
|
pdwAttributes
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Notes: Consider accepting a single STRING
|
|
//
|
|
ASSERT(dwDataType == MULTISZ_METADATA);
|
|
|
|
DWORD err = ConvertDoubleNullListToStringList(
|
|
lpData,
|
|
strlValue,
|
|
dwSize / sizeof(TCHAR)
|
|
);
|
|
hr = HRESULT_FROM_WIN32(err);
|
|
}
|
|
|
|
if (lpData)
|
|
{
|
|
FreeMem(lpData);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::QueryValue(
|
|
IN DWORD dwID,
|
|
IN OUT CBlob & blValue,
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
OUT DWORD * pdwAttributes OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fetch data as a binary blob
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
DWORD CBlob & blValue : Returns the binary blob
|
|
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path off the open key
|
|
DWORD * pdwAttributes : Optionally returns attributes
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Get GetData allocate the buffer for us
|
|
//
|
|
DWORD dwSize = 0;
|
|
DWORD dwDataType = BINARY_METADATA;
|
|
LPBYTE pbData = NULL;
|
|
|
|
HRESULT hr = GetPropertyValue(
|
|
dwID,
|
|
dwSize,
|
|
(void *&)pbData,
|
|
&dwDataType,
|
|
pfInheritanceOverride,
|
|
lpszMDPath,
|
|
pdwAttributes
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Blob takes ownership of the data, so don't free it...
|
|
//
|
|
ASSERT_READ_PTR2(pbData, dwSize);
|
|
blValue.SetValue(dwSize, pbData, FALSE);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::SetValue(
|
|
IN DWORD dwID,
|
|
IN CStringListEx & strlValue,
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store data as string
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
CStringListEx & strlValue : Value to be written
|
|
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path (or NULL or "")
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
DWORD cCharacters;
|
|
LPTSTR lpstr = NULL;
|
|
|
|
//
|
|
// Flatten value
|
|
//
|
|
ConvertStringListToDoubleNullList(
|
|
strlValue,
|
|
cCharacters,
|
|
lpstr
|
|
);
|
|
|
|
HRESULT hr = SetPropertyValue(
|
|
dwID,
|
|
cCharacters * sizeof(TCHAR),
|
|
(void *)lpstr,
|
|
pfInheritanceOverride,
|
|
lpszMDPath
|
|
);
|
|
|
|
SAFE_FREEMEM(lpstr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::SetValue(
|
|
IN DWORD dwID,
|
|
IN CBlob & blValue,
|
|
IN BOOL * pfInheritanceOverride, OPTIONAL
|
|
IN LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store data as binary
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID
|
|
CBlob & blValue : Value to be written
|
|
BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
|
|
LPCTSTR lpszMDPath : Optional path (or NULL or "")
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
return SetPropertyValue(
|
|
dwID,
|
|
blValue.GetSize(),
|
|
(void *)blValue.GetData(),
|
|
pfInheritanceOverride,
|
|
lpszMDPath
|
|
);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::DeleteValue(
|
|
DWORD dwID,
|
|
LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete data
|
|
|
|
Arguments:
|
|
|
|
DWORD dwID : Property ID of property to be deleted
|
|
LPCTSTR lpszMDPath : Optional path (or NULL or "")
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
ASSURE_OPEN_KEY();
|
|
|
|
METADATA_RECORD mdRecord;
|
|
FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
|
|
|
|
return DeleteData(
|
|
m_hKey,
|
|
lpszMDPath,
|
|
mdRecord.dwMDIdentifier,
|
|
mdRecord.dwMDDataType
|
|
);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaKey::DoesPathExist(
|
|
IN LPCTSTR lpszMDPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if the path exists
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszMDPath : Relative path off the open key
|
|
|
|
Return Value:
|
|
|
|
HRESULT, or S_OK if the path exists.
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
ASSURE_OPEN_KEY();
|
|
|
|
FILETIME ft;
|
|
|
|
return GetLastChangeTime(m_hKey, lpszMDPath, &ft, FALSE);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaInterface::Regenerate()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempt to recreate the interface pointer. This assumes that the interface
|
|
had been successfully created before, but has become invalid at some
|
|
point afterwards.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PTR(m_pInterface); // Must have been initialised
|
|
|
|
SAFE_RELEASE(m_pInterface);
|
|
|
|
m_hrInterface = Create();
|
|
|
|
return m_hrInterface;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CWamInterface class
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
CWamInterface::CWamInterface(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct and initialize the interface.
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CIISInterface(pAuthInfo),
|
|
m_pInterface(NULL),
|
|
m_fSupportsPooledProc(FALSE)
|
|
{
|
|
//
|
|
// Initialize the interface
|
|
//
|
|
m_hrInterface = Create();
|
|
}
|
|
|
|
|
|
|
|
CWamInterface::CWamInterface(
|
|
IN CWamInterface * pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct from existing interface (copy constructor)
|
|
|
|
Arguments:
|
|
|
|
CWamInterface * pInterface : Existing interface
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
|
|
m_pInterface(pInterface->m_pInterface),
|
|
m_fSupportsPooledProc(FALSE)
|
|
{
|
|
ASSERT_PTR(m_pInterface);
|
|
m_pInterface->AddRef();
|
|
}
|
|
|
|
|
|
|
|
CWamInterface::~CWamInterface()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor -- releases the interface.
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
SAFE_RELEASE(m_pInterface);
|
|
}
|
|
|
|
|
|
|
|
/* protected */
|
|
HRESULT
|
|
CWamInterface::Create()
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create the interface with DCOM
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
HRESULT
|
|
|
|
Notes:
|
|
First, it will attempt to create the new interface, if it
|
|
fails, it will attempt to create the downlevel interface
|
|
|
|
--*/
|
|
{
|
|
CLSID rgCLSID[2];
|
|
IID rgIID[2];
|
|
|
|
rgCLSID[1] = rgCLSID[0] = CLSID_WamAdmin;
|
|
rgIID[0] = IID_IWamAdmin2;
|
|
rgIID[1] = IID_IWamAdmin;
|
|
|
|
ASSERT(ARRAY_SIZE(rgCLSID) == ARRAY_SIZE(rgIID));
|
|
int cInterfaces = ARRAY_SIZE(rgCLSID);
|
|
int iInterface;
|
|
|
|
HRESULT hr = CIISInterface::Create(
|
|
cInterfaces,
|
|
rgIID,
|
|
rgCLSID,
|
|
&iInterface,
|
|
(IUnknown **)&m_pInterface
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Only supported on IWamAdmin2
|
|
//
|
|
m_fSupportsPooledProc = (rgIID[iInterface] == IID_IWamAdmin2);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CWamInterface::AppCreate(
|
|
IN LPCTSTR szMDPath,
|
|
IN DWORD dwAppProtection
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create application
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR szMDPath : Metabase path
|
|
DWORD dwAppProtection : APP_INPROC to create in-proc app
|
|
APP_OUTOFPROC to create out-of-proc app
|
|
APP_POOLEDPROC to create a pooled-proc app
|
|
|
|
Return Value:
|
|
|
|
HRESULT (ERROR_INVALID_PARAMETER if unsupported protection state is requested)
|
|
|
|
--*/
|
|
{
|
|
if (m_fSupportsPooledProc)
|
|
{
|
|
//
|
|
// Interface pointer is really IWamAdmin2, so call the new method
|
|
//
|
|
return ((IWamAdmin2 *)m_pInterface)->AppCreate2(szMDPath, dwAppProtection);
|
|
}
|
|
|
|
//
|
|
// Call the downlevel API
|
|
//
|
|
if (dwAppProtection == APP_INPROC || dwAppProtection == APP_OUTOFPROC)
|
|
{
|
|
BOOL fInProc = (dwAppProtection == APP_INPROC);
|
|
|
|
ASSERT_PTR(m_pInterface);
|
|
return m_pInterface->AppCreate(szMDPath, fInProc);
|
|
}
|
|
|
|
return CError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CMetaback Class
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
const LPCTSTR CMetaBack::s_szMasterAppRoot =\
|
|
SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR SZ_MBN_WEB;
|
|
|
|
|
|
CMetaBack::CMetaBack(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor for metabase backup/restore operations class. This object
|
|
is both a WAM interface and a METABASE interface.
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_dwIndex(0),
|
|
CMetaInterface(pAuthInfo),
|
|
CWamInterface(pAuthInfo)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
BOOL
|
|
CMetaBack::Succeeded() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if object was constructed successfully.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
{
|
|
return CMetaInterface::Succeeded() && CWamInterface::Succeeded();
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CMetaBack::QueryResult() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the construction error for this object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT from construction errors
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Both interfaces must have constructed successfully
|
|
//
|
|
HRESULT hr = CMetaInterface::QueryResult();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CWamInterface::QueryResult();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaBack::Restore(
|
|
IN LPCTSTR lpszLocation,
|
|
IN DWORD dwVersion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Restore metabase
|
|
|
|
Arguments:
|
|
|
|
DWORD dwVersion : Backup version
|
|
LPCTSTR lpszLocation : Backup location
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Backup and restore the application information from a restore
|
|
//
|
|
CString strPath(s_szMasterAppRoot);
|
|
HRESULT hr = AppDeleteRecoverable(strPath, TRUE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CMetaInterface::Restore(lpszLocation, dwVersion, 0);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = AppRecover(strPath, TRUE);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CMetaBack::BackupWithPassword(
|
|
IN LPCTSTR lpszLocation,
|
|
IN LPCTSTR lpszPassword
|
|
)
|
|
{
|
|
return CMetaInterface::BackupWithPassword(
|
|
lpszLocation,
|
|
MD_BACKUP_NEXT_VERSION,
|
|
MD_BACKUP_SAVE_FIRST,
|
|
lpszPassword
|
|
);
|
|
}
|
|
|
|
HRESULT
|
|
CMetaBack::RestoreWithPassword(
|
|
IN LPCTSTR lpszLocation,
|
|
IN DWORD dwVersion,
|
|
IN LPCTSTR lpszPassword
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Restore metabase
|
|
|
|
Arguments:
|
|
|
|
DWORD dwVersion : Backup version
|
|
LPCTSTR lpszLocation : Backup location
|
|
LPCTSTR lpszPassword : Backup password
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Backup and restore the application information from a restore
|
|
//
|
|
// BUGBUG: clear it out, why we had an error "parameter is incorrect" from AppDeleteRecoverable
|
|
CString strPath(s_szMasterAppRoot);
|
|
HRESULT hr;// = AppDeleteRecoverable(strPath, TRUE);
|
|
|
|
// if (SUCCEEDED(hr))
|
|
// {
|
|
hr = CMetaInterface::RestoreWithPassword(lpszLocation, dwVersion, 0, lpszPassword);
|
|
|
|
// if (SUCCEEDED(hr))
|
|
// {
|
|
// hr = AppRecover(strPath, TRUE);
|
|
// }
|
|
// }
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// CIISSvcControl class
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
CIISSvcControl::CIISSvcControl(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct and initialize the interface.
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CIISInterface(pAuthInfo),
|
|
m_pInterface(NULL)
|
|
{
|
|
//
|
|
// Initialize the interface
|
|
//
|
|
m_hrInterface = Create();
|
|
}
|
|
|
|
|
|
|
|
CIISSvcControl::CIISSvcControl(
|
|
IN CIISSvcControl * pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct from existing interface (copy constructor)
|
|
|
|
Arguments:
|
|
|
|
CIISSvcControl * pInterface : Existing interface
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
|
|
m_pInterface(pInterface->m_pInterface)
|
|
{
|
|
ASSERT_PTR(m_pInterface);
|
|
m_pInterface->AddRef();
|
|
}
|
|
|
|
|
|
|
|
CIISSvcControl::~CIISSvcControl()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor -- releases the interface.
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
SAFE_RELEASE(m_pInterface);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CMetaEnumerator Clas
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
CMetaEnumerator::CMetaEnumerator(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL,
|
|
IN LPCTSTR lpszMDPath OPTIONAL,
|
|
IN METADATA_HANDLE hkBase OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Metabase enumerator constructor. This constructor creates a new interface
|
|
and opens a key.
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
|
|
LPCTSTR lpszMDPath : Metabase path
|
|
METADATA_HANDLE hkBase : Metabase handle
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CMetaKey(pAuthInfo, lpszMDPath, METADATA_PERMISSION_READ, hkBase),
|
|
m_dwIndex(0L)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
CMetaEnumerator::CMetaEnumerator(
|
|
IN CMetaInterface * pInterface,
|
|
IN LPCTSTR lpszMDPath, OPTIONAL
|
|
IN METADATA_HANDLE hkBase OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Metabase enumerator constructor. This constructor uses an existing
|
|
interface and opens a key.
|
|
|
|
Arguments:
|
|
|
|
CMetaInterface * pInterface : Existing interface
|
|
LPCTSTR lpszMDPath : Metabase path
|
|
METADATA_HANDLE hkBase : Metabase handle
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CMetaKey(pInterface, lpszMDPath, METADATA_PERMISSION_READ, hkBase),
|
|
m_dwIndex(0L)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
CMetaEnumerator::CMetaEnumerator(
|
|
IN BOOL fOwnKey,
|
|
IN CMetaKey * pKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Metabase enumerator constructor. This constructor uses an existing
|
|
interface and open key.
|
|
|
|
Arguments:
|
|
|
|
BOOL fOwnKey : TRUE if we own the key (destructor will close)
|
|
CMetaKey * pKey : Open key
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CMetaKey(fOwnKey, pKey),
|
|
m_dwIndex(0L)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaEnumerator::Next(
|
|
OUT CString & strKey,
|
|
IN LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the next subkey
|
|
|
|
Arguments:
|
|
|
|
CString & str Returns keyname
|
|
LPCTSTR lpszMDPath Optional subpath
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
ASSURE_OPEN_KEY();
|
|
|
|
LPTSTR lpKey = strKey.GetBuffer(MAX_PATH);
|
|
HRESULT hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++);
|
|
strKey.ReleaseBuffer();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMetaEnumerator::Next(
|
|
OUT DWORD & dwKey,
|
|
OUT CString & strKey,
|
|
IN LPCTSTR lpszMDPath OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the next subkey as a DWORD. This skips non-numeric
|
|
keynames (including 0) until the first numeric key name
|
|
|
|
Arguments:
|
|
|
|
DWORD & dwKey Numeric key
|
|
CString & strKey Same key in string format
|
|
LPCTSTR lpszMDPath Optional subpath
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSURE_PROPER_INTERFACE();
|
|
ASSURE_OPEN_KEY();
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL fContinue = TRUE;
|
|
|
|
while (fContinue)
|
|
{
|
|
fContinue = FALSE;
|
|
|
|
LPTSTR lpKey = strKey.GetBuffer(MAX_PATH);
|
|
hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++);
|
|
strKey.ReleaseBuffer();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (FALSE == (dwKey = _ttoi((LPCTSTR)strKey)))
|
|
{
|
|
//
|
|
// Ignore this one
|
|
//
|
|
fContinue = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CIISApplication class
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<</
|
|
|
|
|
|
|
|
CIISApplication::CIISApplication(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL,
|
|
IN LPCTSTR lpszMetapath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct IIS application.
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Authentication info. NULL indicates the
|
|
local computer.
|
|
LPCTSTR lpszMetapath : Metabase path
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CWamInterface(pAuthInfo),
|
|
CMetaKey(pAuthInfo),
|
|
m_dwProcessProtection(APP_INPROC),
|
|
m_dwAppState(APPSTATUS_NOTDEFINED),
|
|
m_strFriendlyName(),
|
|
m_strAppRoot(),
|
|
m_strWamPath(lpszMetapath)
|
|
{
|
|
CommonConstruct();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CIISApplication::CommonConstruct()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform common construction
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Munge the metapath so that WAM doesn't cough up a hairball.
|
|
//
|
|
|
|
|
|
//
|
|
// BUGBUG: CleanMetaPath() disabled currently
|
|
//
|
|
|
|
if (m_strWamPath[0] != SZ_MBN_SEP_CHAR)
|
|
{
|
|
m_strWamPath = SZ_MBN_SEP_CHAR + m_strWamPath;
|
|
}
|
|
|
|
do
|
|
{
|
|
m_hrApp = CWamInterface::QueryResult();
|
|
|
|
if (FAILED(m_hrApp))
|
|
{
|
|
break;
|
|
}
|
|
|
|
m_hrApp = RefreshAppState();
|
|
|
|
if (HRESULT_CODE(m_hrApp) == ERROR_PATH_NOT_FOUND)
|
|
{
|
|
//
|
|
// "Path Not Found" errors are acceptable, since
|
|
// the application may not yet exist.
|
|
//
|
|
m_hrApp = S_OK;
|
|
}
|
|
}
|
|
while(FALSE);
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
BOOL
|
|
CIISApplication::Succeeded() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if object was constructed successfully
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
{
|
|
return CMetaInterface::Succeeded()
|
|
&& CWamInterface::Succeeded()
|
|
&& SUCCEEDED(m_hrApp);
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISApplication::QueryResult() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the construction error for this object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT from construction errors
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Both interfaces must have constructed successfully
|
|
//
|
|
HRESULT hr = CMetaInterface::QueryResult();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CWamInterface::QueryResult();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_hrApp;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISApplication::RefreshAppState()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Refresh the application state
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT(!m_strWamPath.IsEmpty());
|
|
|
|
HRESULT hr, hrKeys;
|
|
|
|
hr = AppGetStatus(m_strWamPath, &m_dwAppState);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
m_dwAppState = APPSTATUS_NOTDEFINED;
|
|
}
|
|
|
|
m_strAppRoot.Empty();
|
|
hrKeys = QueryValue(MD_APP_ROOT, m_strAppRoot, NULL, m_strWamPath);
|
|
|
|
m_dwProcessProtection = APP_INPROC;
|
|
hrKeys = QueryValue(
|
|
MD_APP_ISOLATED,
|
|
m_dwProcessProtection,
|
|
NULL,
|
|
m_strWamPath
|
|
);
|
|
|
|
hrKeys = QueryValue(
|
|
MD_APP_APPPOOL_ID,
|
|
m_strAppPoolId,
|
|
NULL,
|
|
m_strWamPath
|
|
);
|
|
|
|
m_strFriendlyName.Empty();
|
|
hrKeys = QueryValue(
|
|
MD_APP_FRIENDLY_NAME,
|
|
m_strFriendlyName,
|
|
NULL,
|
|
m_strWamPath
|
|
);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CIISApplication::Create(
|
|
IN LPCTSTR lpszName, OPTIONAL
|
|
IN DWORD dwAppProtection
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create the application
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszName : Application name
|
|
DWORD dwAppProtection : APP_INPROC to create in-proc app
|
|
APP_OUTOFPROC to create out-of-proc app
|
|
APP_POOLEDPROC to create a pooled-proc app
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT(!m_strWamPath.IsEmpty());
|
|
HRESULT hr = AppCreate(m_strWamPath, dwAppProtection);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Write the friendly app name, which we maintain
|
|
// ourselves. Empty it first, because we might
|
|
// have picked up a name from inheritance.
|
|
//
|
|
m_strFriendlyName.Empty();
|
|
hr = WriteFriendlyName(lpszName);
|
|
|
|
RefreshAppState();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CIISApplication::CreatePooled(
|
|
LPCTSTR name,
|
|
DWORD mode,
|
|
LPCTSTR pool_id,
|
|
BOOL fCreatePool)
|
|
{
|
|
ASSERT(!m_strWamPath.IsEmpty());
|
|
ASSERT(NULL != pool_id);
|
|
HRESULT hr = CreateApplication(m_strWamPath, mode, pool_id, fCreatePool);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_strFriendlyName.Empty();
|
|
hr = WriteFriendlyName(name);
|
|
RefreshAppState();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CIISApplication::WriteFriendlyName(
|
|
IN LPCTSTR lpszName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write the friendly name. This will not write anything
|
|
if the name is the same as it was
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszName : New friendly name
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_strFriendlyName.CompareNoCase(lpszName) != 0)
|
|
{
|
|
hr = Open(METADATA_PERMISSION_WRITE, m_strWamPath);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT_PTR(lpszName);
|
|
|
|
CString str(lpszName);
|
|
hr = SetValue(MD_APP_FRIENDLY_NAME, str);
|
|
Close();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_strFriendlyName = lpszName;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CIISApplication::WritePoolId(LPCTSTR id)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_strAppPoolId.CompareNoCase(id) != 0)
|
|
{
|
|
hr = Open(METADATA_PERMISSION_WRITE, m_strWamPath);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT_PTR(id);
|
|
|
|
CString str(id);
|
|
hr = SetValue(MD_APP_APPPOOL_ID, str);
|
|
Close();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_strAppPoolId = id;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// CIISAppPool class
|
|
|
|
CIISAppPool::CIISAppPool(
|
|
IN CComAuthInfo * pAuthInfo OPTIONAL,
|
|
IN LPCTSTR lpszMetapath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct IIS application pool.
|
|
|
|
Arguments:
|
|
|
|
CComAuthInfo * pAuthInfo : Authentication info. NULL indicates the
|
|
local computer.
|
|
LPCTSTR lpszMetapath : Metabase path
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CWamInterface(pAuthInfo),
|
|
CMetaKey(pAuthInfo),
|
|
m_dwPoolState(0),
|
|
m_strFriendlyName(),
|
|
m_strWamPath(lpszMetapath)
|
|
{
|
|
if (m_strWamPath[0] != SZ_MBN_SEP_CHAR)
|
|
{
|
|
m_strWamPath = SZ_MBN_SEP_CHAR + m_strWamPath;
|
|
}
|
|
|
|
do
|
|
{
|
|
if (FAILED(m_hrPool = CWamInterface::QueryResult()))
|
|
{
|
|
break;
|
|
}
|
|
if (MD_ERROR_DATA_NOT_FOUND == (m_hrPool = RefreshState())
|
|
|| HRESULT_CODE(m_hrPool) == ERROR_PATH_NOT_FOUND)
|
|
{
|
|
//
|
|
// "Path Not Found" errors are acceptable, since
|
|
// the pool may not yet exist.
|
|
//
|
|
m_hrPool = S_OK;
|
|
}
|
|
}
|
|
while(FALSE);
|
|
}
|
|
|
|
HRESULT
|
|
CIISAppPool::RefreshState()
|
|
{
|
|
ASSERT(!m_strWamPath.IsEmpty());
|
|
|
|
HRESULT hr;
|
|
|
|
m_strFriendlyName.Empty();
|
|
hr = QueryValue(
|
|
MD_APPPOOL_FRIENDLY_NAME,
|
|
m_strFriendlyName,
|
|
NULL,
|
|
m_strWamPath
|
|
);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISAppPool::QueryResult() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the construction error for this object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT from construction errors
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Both interfaces must have constructed successfully
|
|
//
|
|
HRESULT hr = CMetaInterface::QueryResult();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CWamInterface::QueryResult();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_hrPool;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* virtual */
|
|
BOOL
|
|
CIISAppPool::Succeeded() const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if object was constructed successfully
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE for success, FALSE for failure
|
|
|
|
--*/
|
|
{
|
|
return CMetaInterface::Succeeded()
|
|
&& CWamInterface::Succeeded()
|
|
&& SUCCEEDED(m_hrPool);
|
|
}
|
|
|
|
HRESULT
|
|
CIISAppPool::EnumerateApplications(CStringListEx& apps)
|
|
{
|
|
CString pool;
|
|
BSTR bstr = NULL;
|
|
|
|
CMetabasePath::GetLastNodeName(m_strWamPath, pool);
|
|
CError err = CWamInterface::EnumerateApplicationsInPool(
|
|
pool, &bstr);
|
|
if (err.Succeeded())
|
|
{
|
|
ConvertDoubleNullListToStringList(bstr, apps);
|
|
}
|
|
#ifdef _DEBUG
|
|
err.MessageBoxOnFailure();
|
|
#endif
|
|
SysFreeString(bstr);
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISAppPool::Create(LPCTSTR name)
|
|
{
|
|
CString id;
|
|
if (name != NULL)
|
|
{
|
|
id = name;
|
|
}
|
|
else
|
|
{
|
|
CMetabasePath::GetLastNodeName(m_strWamPath, id);
|
|
}
|
|
CError err = CWamInterface::CreateApplicationPool(id);
|
|
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISAppPool::Delete(LPCTSTR id)
|
|
{
|
|
CError err = CWamInterface::DeleteApplicationPool(id);
|
|
|
|
return err;
|
|
}
|
|
|