#include "stdafx.h"
#include "api.h"
#include "depsettings.h"
#include "resource.h"
#include <adserr.h>
#define INITGUID // must be before iadmw.h
#include <iadmw.h> // Interface header
// for the IID_IISWebService object
#include "iiisext.h"
#include "iisext_i.c"
#pragma warning(disable:4571) //catch(...) blocks compiled with /EHs do NOT catch or re-throw Structured Exceptions
class CIISMutex
{
public:
HANDLE hMutex;
CIISMutex()
{
hMutex = ::CreateMutex(NULL, FALSE, _T("VC8_VCDEPLOY"));
}
bool Lock()
{
printf("Trying to lock mutex %lx/n", (DWORD_PTR)hMutex);
DWORD dw = WaitForSingleObject(hMutex, 10000);
return (dw == WAIT_OBJECT_0);
}
~CIISMutex()
{
printf("Releasing mutex %lx/n", (DWORD_PTR)hMutex);
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
};
HRESULT AddWebSvcExtention(WCHAR* wszRootWeb6, LPWSTR lpwszFileName,VARIANT_BOOL bEnabled,LPWSTR lpwszGroupID,VARIANT_BOOL bDeletableThruUI,LPWSTR lpwszGroupDescription)
{
HRESULT hrRet = S_FALSE;
CComPtr<IISWebService> spWeb;
HRESULT hr = ADsGetObject(wszRootWeb6, IID_IISWebService, (void**)&spWeb);
if (SUCCEEDED(hr) && spWeb != NULL)
{
CComVariant var1, var2;
var1.vt = VT_BOOL;
var1.boolVal = bEnabled;
var2.vt = VT_BOOL;
var2.boolVal = bDeletableThruUI;
CComBSTR bstrFileName(lpwszFileName);
CComBSTR bstrGroupID(lpwszGroupID);
CComBSTR bstrGroupDescription(lpwszGroupDescription);
hr = spWeb->AddExtensionFile(bstrFileName,var1,bstrGroupID,var2,bstrGroupDescription);
if (SUCCEEDED(hr))
{
hrRet = S_OK;
}
else
{
OutputDebugString(_T("failed,probably already exists/r/n"));
}
VariantClear(&var1);
VariantClear(&var2);
}
return hrRet;
}
HRESULT RemoveWebSvcExtention(WCHAR* wszRootWeb6, LPWSTR lpwszFileName)
{
HRESULT hrRet = S_FALSE;
IISWebService * pWeb = NULL;
HRESULT hr = ADsGetObject(wszRootWeb6, IID_IISWebService, (void**)&pWeb);
if (SUCCEEDED(hr) && NULL != pWeb)
{
CComBSTR bstrFileName(lpwszFileName);
hr = pWeb->DeleteExtensionFileRecord(bstrFileName);
if (SUCCEEDED(hr))
{
hrRet = S_OK;
}
else
{
OutputDebugString(_T("failed,probably already gone/r/n"));
}
pWeb->Release();
}
return hrRet;
}
HRESULT AddApplicationDependencyUponGroup(WCHAR* wszRootWeb6, LPWSTR lpwszAppName,LPWSTR lpwszGroupID)
{
HRESULT hrRet = S_FALSE;
IISWebService * pWeb = NULL;
HRESULT hr = ADsGetObject(wszRootWeb6, IID_IISWebService, (void**)&pWeb);
if (SUCCEEDED(hr) && NULL != pWeb)
{
CComBSTR bstrAppName(lpwszAppName);
CComBSTR bstrGroupID(lpwszGroupID);
hr = pWeb->AddDependency(bstrAppName,bstrGroupID);
if (SUCCEEDED(hr))
{
hrRet = S_OK;
}
else
{
OutputDebugString(_T("failed,probably already exists/r/n"));
}
pWeb->Release();
}
return hrRet;
}
HRESULT RemoveApplicationDependencyUponGroup(WCHAR* wszRootWeb6, LPWSTR lpwszAppName,LPWSTR lpwszGroupID)
{
HRESULT hrRet = S_FALSE;
IISWebService * pWeb = NULL;
HRESULT hr = ADsGetObject(wszRootWeb6, IID_IISWebService, (void**)&pWeb);
if (SUCCEEDED(hr) && NULL != pWeb)
{
CComBSTR bstrAppName(lpwszAppName);
CComBSTR bstrGroupID(lpwszGroupID);
hr = pWeb->RemoveDependency(bstrAppName,bstrGroupID);
if (SUCCEEDED(hr))
{
hrRet = S_OK;
}
else
{
OutputDebugString(_T("failed,probably already gone/r/n"));
}
pWeb->Release();
}
return hrRet;
}
LPSTR _ReverseFind(LPSTR szStr, size_t nLen, char ch)
{
LPSTR sz = szStr+nLen;
while (sz >= szStr)
{
if (*sz == ch)
{
return sz;
}
--sz;
}
return NULL;
}
BOOL RecursiveCreateDirectoryHelper(LPSTR szPath, size_t nLen)
{
WIN32_FILE_ATTRIBUTE_DATA fad;
BOOL bRet;
LPSTR szCurrent;
char chTmp;
memset(&fad, 0x00, sizeof(fad));
bRet = ::GetFileAttributesExA(szPath, GetFileExInfoStandard, &fad);
if (!bRet)
{
if ((GetLastError() == ERROR_PATH_NOT_FOUND) ||
(GetLastError() == ERROR_FILE_NOT_FOUND))
{
szCurrent = _ReverseFind(szPath, nLen, '//');
if (szCurrent != NULL)
{
nLen -= (szPath-szCurrent);
chTmp = *szCurrent;
*szCurrent = '/0';
bRet = RecursiveCreateDirectoryHelper(szPath, nLen);
if (!bRet)
{
return bRet;
}
*szCurrent = chTmp;
bRet = ::CreateDirectory(szPath, NULL);
// VSW#472354 - There is a race condition where if two projects are
// building at the same time, the deployment of the other can cause
// this directory to get created after we check that it doesn't exist.
if (!bRet && (GetLastError() != ERROR_ALREADY_EXISTS))
{
return bRet;
}
}
}
}
return TRUE;
}
BOOL RecursiveCreateDirectory(LPCSTR szDir)
{
char szPath[MAX_PATH];
size_t nLen;
nLen = strlen(szDir);
if (nLen >= MAX_PATH)
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
memcpy(szPath, szDir, nLen);
szPath[nLen] = '/0';
return RecursiveCreateDirectoryHelper(szPath, nLen);
}
int PrintWarning(unsigned int nMsgID)
{
return PrintMessage(_T("warning"), nMsgID, NULL);
}
int PrintWarning(unsigned int nMsgID, TCHAR *szExtraInfo)
{
return PrintMessage(_T("warning"), nMsgID, szExtraInfo);
}
int PrintWarningWithLastWin32(unsigned int nMsgID)
{
TCHAR szMsg[512];
if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
NULL,
szMsg,
512,
NULL))
{
return PrintWarning(nMsgID, szMsg);
}
return PrintWarning(nMsgID);
}
int PrintWarningFormatted(LPCTSTR szWarning)
{
return PrintMessage(_T("warning"), szWarning, NULL);
}
int PrintError(unsigned int nMsgID)
{
return PrintMessage(_T("error"), nMsgID, NULL);
}
int PrintError(unsigned int nMsgID, LPCTSTR szExtraInfo)
{
return PrintMessage(_T("error"), nMsgID, szExtraInfo);
}
int PrintErrorWithLastWin32(unsigned int nMsgID)
{
TCHAR szMsg[512];
if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
NULL,
szMsg,
512,
NULL))
{
return PrintError(nMsgID, szMsg);
}
return PrintError(nMsgID);
}
int PrintErrorFormatted(LPCTSTR szError)
{
return PrintMessage(_T("error"), szError, NULL);
}
int PrintMessage(LPCTSTR szPrefix, unsigned int nMsgID, LPCTSTR szExtraInfo)
{
CString strMsg;
if (!LoadStringFromModule(nMsgID, strMsg))
_tprintf("Failed to load error string %x/n", nMsgID);
else
{
return PrintMessage(szPrefix, (LPCTSTR)strMsg, szExtraInfo);
}
return 0;
}
int PrintMessage(LPCTSTR szPrefix, LPCTSTR szMsg, LPCTSTR szExtraInfo)
{
if (szExtraInfo)
_tprintf("vcdeploy : %s %s %s./n", szPrefix, szMsg, szExtraInfo);
else
_tprintf("vcdeploy : %s %s/n", szPrefix, szMsg);
return ATLSDPLY_SUCCESS;
}
int PrintMessage(unsigned int nMsgID)
{
CString strMsg;
if (!LoadStringFromModule(nMsgID, strMsg))
_tprintf("Failed to load error string %x/n", nMsgID);
else
{
_tprintf("%s/n", static_cast<const char *>(strMsg));
}
return 0;
}
bool FormatMsg(CString& strDest, UINT uId, ...)
{
CString strFmt;
if (!strFmt.LoadString(uId))
return false;
va_list argList;
va_start( argList, uId );
strDest.FormatV(strFmt, argList);
va_end( argList );
return true;
}
int ProcessSettings(CDepSettings *pSettings)
{
int result = ATLSDPLY_FAIL;
long nListLen = 0;
CComPtr<IXMLDOMNodeList> spHostList;
if (!pSettings)
{
PrintError(IDS_UNEXPECTED);
return ATLSDPLY_FAIL;
}
// Get the list of host's from the settings object
// We should have already failed loading
// settings if there was no host list.
result = pSettings->GetHostList(&spHostList);
RETURN_ON_UNEXPECTED_HRP(result, spHostList);
result = spHostList->get_length(&nListLen);
RETURN_ON_UNEXPECTED(result);
if (nListLen == 0)
return ATLSDPLY_SUCCESS; // nothing to do
// start processing stuff for each host
CComPtr<IXMLDOMNode> spHostNode;
CComBSTR bstrHost;
for (long i = 0; i<nListLen; i++)
{
CADSIHelper adsHelper;
result = spHostList->get_item(i, &spHostNode);
RETURN_ON_UNEXPECTED_HRP(result, spHostNode);
result = spHostNode->get_text(&bstrHost);
RETURN_ON_UNEXPECTED(result);
if (bstrHost[0] == L'/0')
{
PrintWarning(IDS_WARNING_EMPTY_HOST_TAG);
continue; // empty host name, we'll just press on in this case
}
if (S_OK == (result = CADSIHelper::FastLocalRootCheck(pSettings->GetVirtDirName())))
{
// VRoot exists
// Unload IIS as required by settings document
if (pSettings->GetUnloadBeforeCopy())
{
result = LocalW3svcReset();
RETURN_ON_FAIL(result);
}
// do filesystem updates, this includes creating directories for
// new files and copying filesystem files.
result = UpdateFileSystem(pSettings);
RETURN_ON_FAIL(result);
// result = CheckMinVRootConfigSettings(pSettings);
// if (result == ATLSDPLY_SUCCESS)
// {
// connect to ads to configure the root
result = CheckVRootExistance(bstrHost, &adsHelper, pSettings);
RETURN_ON_FAIL(result);
// configure the virtual directory according to the settings file.
result = ConfigureVRoot(&adsHelper, pSettings, bstrHost);
RETURN_ON_FAIL(result);
// Commit any changes in the metabase.
result = adsHelper.SetInfo();
RETURN_ON_UNEXPECTED(result);
result = CADSIHelper::SaveMetabaseData();
if (result != S_OK)
{
CString strMsg;
FormatMsg(strMsg, IDS_WARNING_FAILED_METABSESAVE, result);
PrintWarningFormatted(strMsg);
}
// }
result = RegisterExtension(&adsHelper, pSettings);
RETURN_ON_FAIL2(result,result);
}
else
{
// copy system files. Has to be done first so we
// don't get errors from IIS.
result = UpdateFileSystem(pSettings);
RETURN_ON_FAIL(result);
// create the virtual directory
result = CreateVRoot(bstrHost, &adsHelper, pSettings);
RETURN_ON_FAIL(result);
// result = CheckMinVRootConfigSettings(pSettings);
// if (result == ATLSDPLY_SUCCESS)
// {
// configure the virtual directory according to the settings file.
result = ConfigureVRoot(&adsHelper, pSettings, bstrHost);
RETURN_ON_FAIL(result);
// }
// Commit any changes in the metabase.
result = adsHelper.SetInfo();
RETURN_ON_UNEXPECTED(result);
result = RegisterExtension(&adsHelper, pSettings);
RETURN_ON_FAIL2(result,result);
// finally, we persist the metabase changes. We don't check
result = CADSIHelper::SaveMetabaseData();
if (result != S_OK)
{
CString strMsg;
FormatMsg(strMsg, IDS_WARNING_FAILED_METABSESAVE, result);
PrintWarningFormatted(strMsg);
}
result = ATLSDPLY_SUCCESS;
}
}
return ATLSDPLY_SUCCESS;
}
int ConfigureRestrictionList(CADSIHelper * /*pAdsHelper*/,
CDepSettings *pSettings,
const wchar_t* wszHost)
{
HRESULT hr = E_FAIL;
try
{
LPCTSTR szvdfspath = pSettings->GetVirtDirFSPath();
LPCTSTR szextfilename = pSettings->GetExtensionFileName();
// need all of these if we are going to get anywhere!
if (szvdfspath == NULL || *szvdfspath == L'/0' ||
szextfilename == NULL || *szextfilename == L'/0' ||
wszHost == NULL || *wszHost == L'/0')
{
return ATLSDPLY_SUCCESS;
}
CStringW strSvc(L"IIS://");
strSvc += wszHost;
strSvc += L"/W3SVC";
if( pSettings->GetIISMajorVer() < 6 )
return ATLSDPLY_SUCCESS;
// create the full path to the isapi
CPathW strIsapiPath;
CStringW strVirtDirPath(szvdfspath);
CStringW strExtFileName(szextfilename);
strIsapiPath.Combine(strVirtDirPath, strExtFileName);
CStringW strDescription( pSettings->GetVirtDirName() );
LPWSTR pwszSvc = const_cast<WCHAR*>((LPCWSTR)strSvc);
LPWSTR pwszIsapiPath = const_cast<WCHAR*>((LPCWSTR)strIsapiPath);
LPWSTR pwszDescription = const_cast<WCHAR*>((LPCWSTR)strDescription);
// Add strIsapiPath to the restrictionlist, make sure it's enabled,
// and that the user is able to remove the entry thru the UI if they wanted to
hr = AddWebSvcExtention( pwszSvc, pwszIsapiPath, VARIANT_TRUE, pwszDescription, VARIANT_TRUE, pwszDescription );
if( hr == S_OK )
{
hr = AddApplicationDependencyUponGroup( pwszSvc, pwszDescription, pwszDescription );
}
if( hr == S_FALSE ) // the strIsapiPath has already been on the restriction list.
hr = S_OK;
}
catch(...)
{
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
}
return hr == S_OK ? ATLSDPLY_SUCCESS : ATLSDPLY_FAIL;
}
/*
int ConfigureRestrictionList(CADSIHelper *pAdsHelper,
CDepSettings *pSettings,
const wchar_t* wszHost)
{
HRESULT hr = E_FAIL;
try
{
LPCTSTR szvdfspath = pSettings->GetVirtDirFSPath();
LPCTSTR szextfilename = pSettings->GetExtensionFileName();
// need all of these if we are going to get anywhere!
if (szvdfspath == NULL || *szvdfspath == L'/0' ||
szextfilename == NULL || *szextfilename == L'/0' ||
wszHost == NULL || *wszHost == L'/0')
{
return ATLSDPLY_SUCCESS;
}
ATLASSERT(pAdsHelper != NULL);
if (!pAdsHelper)
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
CADSIHelper service;
CStringW strSvc(L"IIS://");
strSvc += wszHost;
strSvc += L"/W3SVC";
if (S_OK != service.Connect(strSvc))
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
CComVariant vIRL;
hr = service.GetProperty(L"IsapiRestrictionList", vIRL);
if (hr != S_OK)
{
if (hr != E_ADS_PROPERTY_NOT_SUPPORTED && hr != DISP_E_UNKNOWNNAME)
{
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
}
else
return ATLSDPLY_SUCCESS; // Property only exists on IIS > 6
}
if ( !(vIRL.vt & (VT_ARRAY | VT_VARIANT)) )
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
CComSafeArray<VARIANT> saCurrentList;
saCurrentList.Attach(vIRL.parray);
vIRL.vt = VT_EMPTY;
// The first string in the list is either "1" or "0"
// If it's one, then all ISAPI extensions are allowed to run except
// the ones in the list. Since this is a new vroot for a new extension
// we assume our isapi would not be on the list if the first string is
// "1" so if it is "1", we're done.
// If it's "0" then no isapis are allowed to run except those on the list
// so we need to add ourselves to the list.
// look at the first string
CComVariant v = saCurrentList.GetAt(0);
if (v.vt != VT_BSTR)
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
if (!wcscmp(L"1", v.bstrVal))
return ATLSDPLY_SUCCESS; // we're done, everything is allowed to run
// create the full path to the isapi
CPathW strIsapiPath;
CStringW strVirtDirPath(szvdfspath);
CStringW strExtFileName(szextfilename);
strIsapiPath.Combine(strVirtDirPath, strExtFileName);
// make sure this isapi isn't already in the list and skip
// the first string because it's either "1" or "0"
int count = saCurrentList.GetCount(); // count of dim 0
for (int i=1; i<count; i++)
{
CComVariant &v = saCurrentList.GetAt(i);
if (v.vt == VT_BSTR && !strIsapiPath.m_strPath.Compare(v.bstrVal))
return ATLSDPLY_SUCCESS;
}
// otherwise, add the full path to this isapi to the IRL list
CComSafeArray<VARIANT> saNewList(saCurrentList); // Copies source safearray to our new array
if (!saNewList.m_psa)
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
hr = E_FAIL;
CComVariant vNewItem(strIsapiPath);
hr = saNewList.Add(vNewItem);
if (hr == S_OK)
{
CComVariant vNewList(saNewList); // Copies the safearray into the variant.
hr = service.SetProperty(L"IsapiRestrictionList", vNewList);
if (hr == S_OK)
{
hr = service.SetInfo();
if (hr == S_OK)
{
// Always notify the user that we have enabled
// their ISAPI.
CString strMsg;
CString strPath(strIsapiPath);
FormatMsg(strMsg, IDS_UPDATEIRL, (LPCTSTR)strPath);
_tprintf((LPCTSTR)strMsg);
}
}
}
}
catch(...)
{
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
}
return hr == S_OK ? ATLSDPLY_SUCCESS : ATLSDPLY_FAIL;
}
*/
int CheckVRootExistance(const CComBSTR& bstrHostName,
CADSIHelper *pAdsHelper,
CDepSettings *pSettings)
{
ATLASSERT(pAdsHelper);
ATLASSERT(pSettings);
if (!pAdsHelper || !pSettings)
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
HRESULT hr = E_FAIL;
try
{
CStringW strVirtDirName(pSettings->GetVirtDirName());
CFixedStringT<CStringW, MAX_PATH> strAdsPathRoot(L"IIS://");
strAdsPathRoot += bstrHostName;
TCHAR szBuf[513];
szBuf[0] = _T('/0');
DWORD dwBufSize = (sizeof(szBuf)/sizeof(TCHAR))-1;
// get environment variable for web site (just a number)
dwBufSize = GetEnvironmentVariable(_T("VCDEPLOY_WEBSITE"), szBuf, dwBufSize);
if ((!dwBufSize) || (dwBufSize >= (sizeof(szBuf)/sizeof(TCHAR))))
{
szBuf[0] = _T('1');
dwBufSize = 1;
}
szBuf[dwBufSize] = _T('/0');
// strAdsPathRoot += L"/W3SVC/1/ROOT";
strAdsPathRoot.Append(L"/W3SVC/", sizeof("/W3SVC/")-1);
strAdsPathRoot.Append(CT2CW(szBuf), dwBufSize);
strAdsPathRoot.Append(L"/ROOT", sizeof("/ROOT")-1);
CFixedStringT<CStringW, MAX_PATH> strAdsPathFull(strAdsPathRoot);
strAdsPathFull += _T('/');
strAdsPathFull += strVirtDirName;
// first, see if we can bind to the full path, which would mean the virtual
// directory already exists
hr = pAdsHelper->Connect(strAdsPathFull);
RETURN_ON_UNEXPECTED(hr);
}
catch(...)
{
// catches CString allocation problems
RETURN_ON_FAIL2(hr, IDS_ERR_OUTOFMEM);
}
return hr;
}
int CreateVRoot(const CComBSTR& bstrHostName,
CADSIHelper *pAdsHelper,
CDepSettings *pSettings)
{
HRESULT hr = E_FAIL;
ATLASSERT(pAdsHelper);
ATLASSERT(pSettings);
if (!pAdsHelper || !pSettings)
RETURN_ON_UNEXPECTED(ATLSDPLY_FAIL);
try
{
CStringW strVirtDirName(pSettings->GetVirtDirName());
CFixedStringT<CStringW, MAX_PATH> strAdsPathRoot(L"IIS://");
strAdsPathRoot += bstrHostName;
TCHAR szBuf[513];
szBuf[0] = _T('/0');
DWORD dwBufSize = (sizeof(szBuf)/sizeof(TCHAR))-1;
// get environment variable for web site (just a number)
dwBufSize = GetEnvironmentVariable(_T("VCDEPLOY_WEBSITE"), szBuf, dwBufSize);
if ((!dwBufSize) || (dwBufSize >= (sizeof(szBuf)/sizeof(TCHAR))))
{
szBuf[0] = _T('1');
dwBufSize = 1;
}
szBuf[dwBufSize] = _T('/0');
// strAdsPathRoot += L"/W3SVC/1/ROOT";
strAdsPathRoot.Append(L"/W3SVC/", sizeof("/W3SVC/")-1);
strAdsPathRoot.Append(CT2CW(szBuf), dwBufSize);
strAdsPathRoot.Append(L"/ROOT", sizeof("/ROOT")-1);
// Root doesn't exist, try to create it
hr = pAdsHelper->Connect(strAdsPathRoot);
RETURN_ON_FAIL2(hr, IDS_ERR_CONNECTADSFAILED);
short nIso = (short)pSettings->GetAppIsolation();
if( pSettings->SkipVirtDirCreation() )
{
hr = pAdsHelper->CreateAppOnly(strVirtDirName, nIso, NULL);
RETURN_ON_FAIL2(hr, IDS_ERR_CREATEVROOTFAILED);
}
else
{
//ATLASSERT(nIso >= 0 && nIso <= 2);
hr = pAdsHelper->CreateVRoot(strVirtDirName, nIso, NULL);
RETURN_ON_FAIL2(hr, IDS_ERR_CREATEVROOTFAILED);
// the path to the root must be set at vroot creation time
// it can't be accessed later.
CComVariant val;
val = pSettings->GetVirtDirFSPath();
hr = pAdsHelper->SetProperty(L"Path", val);
RETURN_ON_FAIL2(hr, IDS_ERR_SETADSPROPERTY);
}
}
catch(...)
{
// catches CString allocation problems
RETURN_ON_FAIL2(hr, IDS_ERR_OUTOFMEM);
}
return ATLSDPLY_SUCCESS;
}
int ConfigureVRoot( CADSIHelper *pAdsHelper,
CDepSettings *pSettings,
const wchar_t* wszHost)
{
ATLASSERT(pAdsHelper);
ATLASSERT(pSettings);
if (!pAdsHelper || !pSettings)
return IDS_UNEXPECTED;
HRESULT hr = E_FAIL;
CComVariant val;
// Set some general properties about the vroot
val.vt = VT_BOOL;
val.boolVal = VARIANT_TRUE;
hr = pAdsHelper->SetProperty(L"AccessExecute", val);
RETURN_ON_FAIL2(hr, IDS_ERR_SETADSPROPERTY);
val = pSettings->GetVirtDirName();
hr = pAdsHelper->SetProperty(L"AppPackageName", val);
RETURN_ON_FAIL2(hr, IDS_ERR_SETADSPROPERTY);
CComVariant varOrigName;
hr = pAdsHelper->GetPropertySingle(L"AppFriendlyName", varOrigName);
if (FAILED(hr) || varOrigName.vt != VT_BSTR || ::SysStringLen(varOrigName.bstrVal) == 0)
{
val = pSettings->GetVirtDirName();
hr = pAdsHelper->SetProperty(L"AppFriendlyName", val);
RETURN_ON_FAIL2(hr, IDS_ERR_SETADSPROPERTY);
}
hr = SetRootAppMappings(pAdsHelper, pSettings);
RETURN_ON_FAIL(hr);
hr = ConfigureRestrictionList(pAdsHelper, pSettings, wszHost);
return hr;
}
LONG FindMapping(CComSafeArray<VARIANT> *pArray, BSTR bstrExt)
{
// if the array is empty, then the entry is not there
if (!pArray->m_psa)
return -1;
// find an item that starts with bstrExt followed by ','
CComBSTR bstrFullExt(bstrExt);
bstrFullExt.Append(",");
size_t nLen = wcslen(bstrFullExt);
ULONG ulCount = pArray->GetCount();
for (LONG lIndex=0; lIndex < (LONG) ulCount; lIndex++)
{
CComVariant var;
var = pArray->GetAt(lIndex);
if (var.vt == VT_BSTR && !_wcsnicmp(bstrFullExt, var.bstrVal, nLen))
return lIndex;
}
return -1;
}
int SetRootAppMappings( CADSIHelper *pAdsHelper,
CDepSettings *pSettings)
{
ATLASSERT(pAdsHelper);
ATLASSERT(pSettings);
if (!pAdsHelper || !pSettings)
return IDS_UNEXPECTED;
LPCTSTR szvdfspath = pSettings->GetVirtDirFSPath();
LPCTSTR szextfilename = pSettings->GetExtensionFileName();
if ((!szvdfspath || *szvdfspath == _T('/0') ) ||
(!szextfilename || *szextfilename == _T('/0') )
)
return ATLSDPLY_SUCCESS; // not enough info!
HRESULT hr = E_FAIL;
CStringW rgMappings[MAX_VERB_BLOCKS];
CComPtr<IXMLDOMNodeList> spMappingNodes;
CPathW strIsapiPath;
CStringW strVirtDirPath(szvdfspath);
CStringW strExtFileName(szextfilename);
strIsapiPath.Combine(strVirtDirPath, strExtFileName);
hr = pSettings->GetAppMappingList(&spMappingNodes);
RETURN_ON_UNEXPECTED(hr);
if (!spMappingNodes)
return ATLSDPLY_SUCCESS; // nothing to do
long nMappingCount = 0, i=0;
hr = spMappingNodes->get_length(&nMappingCount);
RETURN_ON_UNEXPECTED(hr);
if (nMappingCount <= 0)
return ATLSDPLY_SUCCESS; // nothing to do
if (nMappingCount > MAX_VERB_BLOCKS)
RETURN_ON_FAIL2(ATLSDPLY_FAIL, ATLS_ERR_TOOMANYVERBBLOCKS);
// get the current script mappings
CComVariant vCurrentMappings;
CComSafeArray<VARIANT> saCurrentMappings;
hr = pAdsHelper->GetProperty(L"ScriptMaps", vCurrentMappings);
if (SUCCEEDED(hr) && (vCurrentMappings.vt == (VT_ARRAY|VT_VARIANT)))
{
VARIANT vVal;
VariantInit(&vVal);
vCurrentMappings.Detach(&vVal);
saCurrentMappings.Attach(vVal.parray);
}
CComBSTR strAttrName(L"fileext");
// loop through the nodes and register the extensions
for (i = 0; i<nMappingCount; i++)
{
CComPtr<IXMLDOMNode> spMappingNode, spExtAttr;
CComPtr<IXMLDOMNamedNodeMap> spAttributes;
CComBSTR bstrExt;
hr = spMappingNodes->get_item(i, &spMappingNode);
RETURN_ON_UNEXPECTED_HRP(hr, spMappingNode);
// get the fileext attribute
hr = spMappingNode->get_attributes(&spAttributes);
RETURN_ON_FAIL2_HRP(hr, spAttributes, IDS_FILEEXTATTR_NOTFOUND);
hr = spAttributes->getNamedItem(strAttrName, &spExtAttr);
RETURN_ON_FAIL2_HRP(hr, spAttributes, IDS_FILEEXTATTR_NOTFOUND);
hr = spExtAttr->get_text(&bstrExt);
RETURN_ON_FAIL2(hr, IDS_FILEEXTATTR_INVALID);
if (bstrExt[0] != L'.')
{
CComBSTR bstrTemp(L".");
bstrTemp += bstrExt;
bstrExt = bstrTemp;
}
// get the list of verbs to map to
CComPtr<IXMLDOMNodeList> spExtVerbList;
long nVerbs = 0;
CComBSTR rgVerbs[MAX_VERB_COUNT];
hr = spMappingNode->selectNodes(CComBSTR(L"VERB"), &spExtVerbList);
if (hr != S_OK)
continue; // no verbs, nothing to do
RETURN_ON_UNEXPECTED_P(spExtVerbList);
hr = spExtVerbList->get_length(&nVerbs);
RETURN_ON_UNEXPECTED(hr);
if (nVerbs == 0)
continue; // no verbs, nothing to do
if (nVerbs > MAX_VERB_COUNT)
{
PrintError(IDS_ERR_TOOMANYVERBS);
return ATLSDPLY_FAIL;
}
CStringW strEntry;
strEntry = bstrExt;
strEntry += L",";
strEntry += strIsapiPath;
if (pSettings->GetIISMajorVer() > 4)
{
strEntry += L",0,"; // we already know nVerbs>0
for (long z = 0; z<nVerbs; z++)
{
CComPtr<IXMLDOMNode> spVerbNode;
CComBSTR bstrVerb;
hr = spExtVerbList->get_item(z, &spVerbNode);
RETURN_ON_UNEXPECTED(hr);
hr = spVerbNode->get_text(&bstrVerb);
RETURN_ON_UNEXPECTED(hr);
strEntry += bstrVerb;
if (z < nVerbs-1)
strEntry += L',';
}
}
else
strEntry += L",0";
LONG lIndex = FindMapping(&saCurrentMappings, bstrExt);
if (lIndex >= 0)
{
// update the entry in the array
CComVariant v(strEntry);
saCurrentMappings.SetAt(lIndex, v, TRUE);
}
else
{
// add as a new entry
rgMappings[i] = strEntry;
}
#ifdef _DEBUG
CString strOut;
strOut.Format("Adding mapping %s/n",CW2A(strEntry));
printf(strOut);
ATLTRACE(L"Adding script mapping %s/n", strEntry);
#endif
}
CComSafeArray<VARIANT> rgsaMappings;
for ( long y = 0; y<nMappingCount; y++)
{
if (rgMappings[y].GetLength() != 0)
{
if (S_OK != rgsaMappings.Add(CComVariant(CComBSTR(rgMappings[y]))))
RETURN_ON_UNEXPECTED(E_FAIL);
}
}
// set the safearray of BSTR
if (saCurrentMappings.m_psa)
{
if (rgsaMappings.m_psa)
saCurrentMappings.Add(rgsaMappings);
CComVariant vSafearray(saCurrentMappings);
vSafearray.vt=VT_ARRAY|VT_VARIANT;
hr = pAdsHelper->SetProperty(L"ScriptMaps", vSafearray);
}
else
{
CComVariant vSafearray(rgsaMappings);
vSafearray.vt=VT_ARRAY|VT_VARIANT;
hr = pAdsHelper->SetProperty(L"ScriptMaps", vSafearray);
}
RETURN_ON_FAIL2(hr, IDS_ERR_SETADSPROPERTY);
return hr;
}
int LocalW3svcReset()
{
// There is a race condition that can happen when deploying two projects
// at the same time. We need to stop/restart IIS as a single operation.
// Use a named mutex that works across processes to serialize this action.
CIISMutex iisMutex;
iisMutex.Lock();
DWORD dwRet = 0;
// open service control manager
SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_ENUMERATE_SERVICE);
if (hScm==NULL)
{
PrintErrorWithLastWin32(IDS_FAILEDOPENSCM);
return ATLSDPLY_FAIL;
}
// open W3SVC
SC_HANDLE hW3Svc = OpenService(hScm, _T("W3SVC"), SERVICE_QUERY_STATUS|SERVICE_START|SERVICE_STOP);
if (hW3Svc==NULL)
{
PrintErrorWithLastWin32(IDS_FAILEDOPENSVC);
CloseServiceHandle(hScm);
return ATLSDPLY_FAIL;
}
// stop W3SVC
SERVICE_STATUS svcStatus;
ZeroMemory(&svcStatus, sizeof(svcStatus));
QueryServiceStatus(hW3Svc, &svcStatus);
if (svcStatus.dwCurrentState == SERVICE_RUNNING)
{
ZeroMemory(&svcStatus, sizeof(svcStatus));
if (!ControlService(hW3Svc, SERVICE_CONTROL_STOP, &svcStatus) &&
GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
{
// couldn't send the control service command plus
// the service isn't already stopped.
PrintErrorWithLastWin32(IDS_FAILEDSTOPCOMMAND);
CloseServiceHandle(hW3Svc);
CloseServiceHandle(hScm);
return ATLSDPLY_FAIL;
}
}
if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
{
printf("stopping W3SVC.");
// Stop is pending, we'll have to wait
for (int i=0;i<1000; i++)
{
// sleep
//Sleep(svcStatus.dwWaitHint != 0 ? svcStatus.dwWaitHint : 100);
Sleep(50);
printf(".");
//interogate
ZeroMemory(&svcStatus, sizeof(svcStatus));
if (!QueryServiceStatus(hW3Svc, &svcStatus))
{
PrintErrorWithLastWin32(IDS_FAILEDQUERYSTATUS);
CloseServiceHandle(hW3Svc);
CloseServiceHandle(hScm);
return ATLSDPLY_FAIL;
}
if (svcStatus.dwCurrentState == SERVICE_STOPPED)
{
// service is stopped
break;
}
}
printf("/n");
}
int nRetryCount=0;
if (svcStatus.dwCurrentState == SERVICE_STOPPED)
{
printf("starting W3SVC.");
ZeroMemory(&svcStatus, sizeof(svcStatus));
if (!StartService(hW3Svc, NULL, NULL))
{
PrintErrorWithLastWin32(IDS_FAILEDSTARTSVC);
CloseServiceHandle(hW3Svc);
CloseServiceHandle(hScm);
return ATLSDPLY_FAIL;
}
// check for pending status
ZeroMemory(&svcStatus, sizeof(svcStatus));
if (!QueryServiceStatus(hW3Svc, &svcStatus))
{
PrintErrorWithLastWin32(IDS_FAILEDQUERYSTATUS);
CloseServiceHandle(hW3Svc);
CloseServiceHandle(hScm);
return ATLSDPLY_FAIL;
}
if (svcStatus.dwCurrentState == SERVICE_START_PENDING)
{
// Start is pending, we'll have to wait.
for (int i=0;i<1000; i++)
{
// sleep
// Sleep(svcStatus.dwWaitHint != 0 ? svcStatus.dwWaitHint : 100);
Sleep(50); //polling is faster than using their hint
//interogate
printf(".");
ZeroMemory(&svcStatus, sizeof(svcStatus));
if (!QueryServiceStatus(hW3Svc, &svcStatus))
{
PrintErrorWithLastWin32(IDS_FAILEDQUERYSTATUS);
CloseServiceHandle(hW3Svc);
CloseServiceHandle(hScm);
return ATLSDPLY_FAIL;
}
//success?
if (svcStatus.dwCurrentState == SERVICE_RUNNING)
{
// service is running! We're done
printf("/n");
break;
}
else if (svcStatus.dwCurrentState == SERVICE_STOPPED)
{
if (nRetryCount > 50)
break;
Sleep(100);
if (!StartService(hW3Svc, NULL, NULL))
{
PrintErrorWithLastWin32(IDS_FAILEDSTARTSVC);
CloseServiceHandle(hW3Svc);
CloseServiceHandle(hScm);
return ATLSDPLY_FAIL;
}
nRetryCount++;
}
}
}
}
else
{
// it never stopped for some reason
PrintError(IDS_ERR_NOSTOPW3SVC);
dwRet = ATLSDPLY_FAIL;
}
// final check to see if it's running
if (svcStatus.dwCurrentState != SERVICE_RUNNING)
{
// service should be running by now
ATLASSERT(FALSE);
PrintError(IDS_ERR_W3SVCFAILEDTOSTART);
dwRet = ATLSDPLY_FAIL;
}
CloseServiceHandle(hW3Svc);
CloseServiceHandle(hScm);
return dwRet;
}
int UpdateFileSystem(CDepSettings *pSettings)
{
CComPtr<IXMLDOMNodeList> spFileGroupsList;
HRESULT hr = E_FAIL;
long nAppFileGroups = 0, i=0;
// Create the vroot root directory
CPath FSPath(pSettings->GetVirtDirFSPath());
if (FSPath.m_strPath.GetLength() != 0 && !FSPath.IsDirectory())
{
if (!CreateDirectory(FSPath, NULL))
{
PrintErrorWithLastWin32(IDS_ERR_CREATING_DIRECTORY);
return ATLSDPLY_FAIL;
}
}
else if (FSPath.m_strPath.GetLength() == 0)
{
PrintError(IDS_ERR_CREATING_DIRECTORY);
return ATLSDPLY_FAIL;
}
hr = pSettings->GetFileGroups(&spFileGroupsList);
RETURN_ON_UNEXPECTED_HRP(hr, spFileGroupsList);
//loop through each app file group
hr = spFileGroupsList->get_length(&nAppFileGroups);
RETURN_ON_UNEXPECTED(hr);
if (nAppFileGroups <= 0)
return ATLSDPLY_SUCCESS; // nothing to do
for (i=0; i<nAppFileGroups; i++)
{
CComPtr<IXMLDOMNode> spAppFileGroupNode;
CComPtr<IXMLDOMNodeList> spFileNodeList;
long nFileNameNodes = 0;
hr = spFileGroupsList->get_item(i, &spAppFileGroupNode);
RETURN_ON_UNEXPECTED_HRP(hr, spAppFileGroupNode);
hr = spAppFileGroupNode->selectNodes(CComBSTR(L"APPFILENAME"), &spFileNodeList);
RETURN_ON_UNEXPECTED_HRP(hr, spFileNodeList);
hr = spFileNodeList->get_length(&nFileNameNodes);
RETURN_ON_UNEXPECTED(hr);
if (nFileNameNodes <=0)
continue; // no files in node.
for (long x=0; x<nFileNameNodes; x++)
{
// for each APPFILENAME in the APPFILEGROUP get the
// SRC and DEST tag and copy the file
CComPtr<IXMLDOMNode> spFileNode, spSrc, spDest;
CComBSTR bstrSrcPath, bstrDestPath;
hr = spFileNodeList->get_item(x, &spFileNode);
RETURN_ON_UNEXPECTED_HRP(hr, spFileNode);
hr = spFileNode->selectSingleNode(CComBSTR(L"SRC"), &spSrc);
RETURN_ON_UNEXPECTED_HRP(hr, spSrc);
hr = spFileNode->selectSingleNode(CComBSTR(L"DEST"), &spDest);
RETURN_ON_UNEXPECTED_HRP(hr, spDest);
hr = spSrc->get_text(&bstrSrcPath);
RETURN_ON_UNEXPECTED(hr);
hr = spDest->get_text(&bstrDestPath);
RETURN_ON_UNEXPECTED(hr);
// src is a full path
// dest is a path relative to the root of the vroot path
// Calculate the full path of the file, then see if the
// directory exists. If it doesn't, create it.
CPath vrDestDir;
vrDestDir.Combine(pSettings->GetVirtDirFSPath(), CW2T(bstrDestPath));
CPath vrDestPath(vrDestDir);
vrDestDir.RemoveFileSpec();
if (!vrDestDir.IsDirectory())
{
if (!RecursiveCreateDirectory(vrDestDir))
{
PrintErrorWithLastWin32(IDS_ERR_CREATING_DIRECTORY_RELATIVE);
return ATLSDPLY_FAIL;
}
}
CW2T szDest(bstrSrcPath);
// Copy the file
int result = CheckFileDiff(szDest, vrDestPath);
if (result == S_FALSE)
{
if (!::CopyFile(szDest, vrDestPath, FALSE))
{
PrintWarningWithLastWin32(IDS_WARN_COPYING_FILE);
}
else
{
CString strMsg;
FormatMsg(strMsg, IDS_COPYFILE_MESSAGE, (LPCTSTR)szDest, (LPCTSTR)vrDestPath);
_fputts(static_cast<const TCHAR *>(strMsg),stdout);
ATLTRACE("Copied %s to %s/n", (LPCTSTR)CW2T(bstrSrcPath), (LPCTSTR)vrDestPath);
}
// Remove the readonly attribute on the destination file
// if it is set.
DWORD dwAttrs = GetFileAttributes(vrDestPath);
if (dwAttrs != 0xFFFFFFFF)
{
if (dwAttrs & FILE_ATTRIBUTE_READONLY)
{
dwAttrs &= ~FILE_ATTRIBUTE_READONLY;
if (!SetFileAttributes(vrDestPath, dwAttrs))
{
ATLTRACE(_T("Failed to remove readonly attribute of target file %s/n"), vrDestPath);
}
}
}
}
else if (result == S_OK)
{
CString strMsg;
FormatMsg(strMsg, IDS_FILES_IDENTICAL, (LPCTSTR) szDest);
_fputts(static_cast<const TCHAR *>(strMsg), stdout);
}
}
}
return ATLSDPLY_SUCCESS;
}
int RegisterExtension(CADSIHelper* /*pAdsHelper*/,
CDepSettings *pSettings)
{
if (!pSettings->GetRegIsapi())
return ATLSDPLY_SUCCESS; // isapi doesn't need to be registered
LPCTSTR szVirtDirPath = pSettings->GetVirtDirFSPath();
LPCTSTR szExtFileName = pSettings->GetExtensionFileName();
if (!szVirtDirPath || *szVirtDirPath == _T('/0'))
{
PrintWarning(IDS_ERR_REGISTERING_NOVDIRPATH);
return ATLSDPLY_SUCCESS;
}
if (!szExtFileName || *szExtFileName == _T('/0'))
{
PrintWarning(IDS_ERR_REGISTERING_NOEXTFILE);
return ATLSDPLY_SUCCESS;
}
CPathW strIsapiPath;
int nRet = IDS_ERR_REGISTERING_EXTENSION;
try
{
CStringW strVirtDirPath(szVirtDirPath);
CStringW strExtFileName(szExtFileName);
strIsapiPath.Combine(strVirtDirPath, strExtFileName);
}
catch(...)
{
// probably an allocation problem with the CStrings
return nRet;
}
HINSTANCE hInstExtension = ::LoadLibraryW(strIsapiPath);
if (!hInstExtension)
return IDS_ERR_REGISTERING_EXTENSION;
PFNRegisterServer pfnRegister = (PFNRegisterServer)GetProcAddress(hInstExtension, _T("DllRegisterServer"));
if (pfnRegister)
{
if (S_OK == pfnRegister())
nRet = ATLSDPLY_SUCCESS;
}
else
return IDS_ERR_REGISTERING_EXTENSION;
FreeLibrary(hInstExtension);
return nRet;
}
BOOL LoadStringFromModule(int nID, CString& str)
{
if (!str.LoadString(nID))
return FALSE;
return TRUE;
}
int CheckMinVRootConfigSettings(CDepSettings *pSettings)
{
if (!pSettings)
return IDS_UNEXPECTED;
// For now, if we don't have an ISAPI extension file name
// or we don't have any script mappings, we can't create an
// atls vroot
LPCTSTR szExtensionFile = pSettings->GetExtensionFileName();
if (!szExtensionFile || *szExtensionFile == _T('/0'))
return ATLSDPLY_FAIL;
CComPtr<IXMLDOMNodeList> spList;
HRESULT hr = pSettings->GetAppMappingList(&spList);
if (hr != S_OK && spList)
return ATLSDPLY_FAIL;
return ATLSDPLY_SUCCESS;
}
int RuntimeCheck()
{
CComPtr<IMSAdminBase> spAdmBase;
HRESULT hr = spAdmBase.CoCreateInstance(CLSID_MSAdminBase);
if (hr != S_OK)
return ATLSDPLY_FAIL;
return ATLSDPLY_SUCCESS;
}
// This function checks the length of the files and then does
// a binary check to see if the files are the same. Since we could
// be copying accross different file systems and the timestamp resolution
// even on our own filesystems isn't that great I decided to do a binary
// compare to see if the files are different. It's expensive in terms of
// memory usage but this process should still run pretty fast because there
// shouldn't be that many files to check and the files shouldn't be that big.
// We don't support checking of files of size greater than ULONG_MAX (4 gig).
HRESULT CheckFileDiff(LPCTSTR szSrcPath, LPCTSTR szDestPath)
{
CAtlFile fSrc, fDest;
HRESULT hr = E_FAIL;
if (S_OK == fSrc.Create(szSrcPath, GENERIC_READ, 0, OPEN_EXISTING))
{
if (S_OK == fDest.Create(szDestPath, GENERIC_READ, 0, OPEN_EXISTING))
{
ULONGLONG lenSrc=0,lenDest=0;
if (S_OK == fSrc.GetSize(lenSrc) &&
S_OK == fDest.GetSize(lenDest))
{
if (lenSrc != lenDest)
hr = S_FALSE;
else
{
if (lenSrc > ULONG_MAX ||
lenDest > ULONG_MAX)
{
hr = E_FAIL;
}
else
{
if (lenSrc > ULONG_MAX ||
lenDest > ULONG_MAX)
hr = E_FAIL;
else
{
CHeapPtr<BYTE> pBuffSrc;
CHeapPtr<BYTE> pBuffDest;
hr = S_OK;
if (!pBuffSrc.Allocate((DWORD)lenSrc))
hr = S_FALSE;
if (hr == S_OK && !pBuffDest.Allocate((DWORD)lenDest))
hr = S_FALSE;
if (hr == S_OK && S_OK != fSrc.Read((LPVOID)(BYTE*)pBuffSrc, (DWORD)lenSrc))
hr = S_FALSE;
if (hr == S_OK && S_OK != fDest.Read((LPVOID)(BYTE*)pBuffDest, (DWORD)lenDest))
hr = S_FALSE;
if (hr == S_OK)
hr = memcmp((LPVOID)(BYTE*)pBuffSrc, (LPVOID)(BYTE*)pBuffDest, (DWORD)lenDest) != 0 ? S_FALSE : S_OK;
}
}
}
}
}
else
hr = S_FALSE; // dest doesn't exist
}
else
{
CString strFormat;
DWORD dwLast = GetLastError();
if (dwLast == ERROR_FILE_NOT_FOUND &&
strFormat.LoadString(IDS_WARN_SOURCE_NOT_EXIST))
{
CString strMsg;
strMsg.Format(strFormat, szSrcPath);
PrintWarningFormatted(strMsg);
}
else
{
if (strFormat.LoadString(IDS_WARN_SOURCE_ACCESS_ERROR))
{
CString strMsg;
strMsg.Format(strFormat, dwLast);
PrintWarningFormatted(strMsg);
}
}
}
return hr;
}
HRESULT ProcessAccessCheck()
{
try
{
HANDLE hToken = NULL;
// Current token will impersonate self
if (!ImpersonateSelf(SecurityImpersonation))
return 0;
if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken))
{
// per Q118626, we check the process token
// if there is no thread token
if (GetLastError() != ERROR_NO_TOKEN)
return E_FAIL;
else
{
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return E_FAIL;
}
}
ATLASSERT(hToken);
CAccessToken myToken;
bool bIsMember = false;
myToken.Attach(hToken);
if (myToken.CheckTokenMembership(Sids::Admins(), &bIsMember))
return bIsMember ? S_OK : S_FALSE;
}
catch(...){ }
return E_UNEXPECTED; // should have returned something before here.
}
HRESULT GetWWWRootPath(const CStringW strWebHostName,CStringW& strPath)
{
CComPtr<IEnumVARIANT> spEnum;
CComPtr<IADsContainer> spCont;
CStringW strIISPath=L"IIS://";
strIISPath+=strWebHostName;
strIISPath+=L"/W3SVC";
HRESULT hr=ADsGetObject(strIISPath.GetString(), IID_IADsContainer, (void**) &spCont);
CComPtr<IADs> spDeploySite;
if (SUCCEEDED(hr) && spCont!=NULL)
{
CComPtr<IUnknown> spUnk;
hr=spCont->get__NewEnum(&spUnk);
if (SUCCEEDED(hr))
{
spCont.Release();
hr=spUnk.QueryInterface(&spEnum);
if (SUCCEEDED(hr))
{
spUnk.Release();
CComVariant var;
CComPtr<IDispatch> spDisp;
ULONG lFetch = 0;
// Enumerate children of IIS service, searching for absolute path to "Default Web Site"
// or if not found, the first web site.
hr = spEnum->Next(1, &var, &lFetch);
while(SUCCEEDED(hr) && lFetch > 0)
{
spDisp = V_DISPATCH(&var);
CComPtr<IADs> spADs;
hr=spDisp.QueryInterface(&spADs);
if (SUCCEEDED(hr) && spADs!=NULL)
{
spDisp.Release();
CComBSTR bstrSchemaClass;
hr=spADs->get_Class(&bstrSchemaClass);
if (SUCCEEDED(hr) && bstrSchemaClass == "IIsWebServer")
{
if (!spDeploySite)
{
spDeploySite=spADs;
}
CComVariant varSiteName;
hr=spADs->Get(L"ServerComment",&varSiteName);
if (SUCCEEDED(hr))
{
CComBSTR bstrSiteName (V_BSTR(&varSiteName));
if (bstrSiteName == "Default Web Site")
{
spDeploySite = spADs;
break;
}
}
}
}
var.Clear();
hr = spEnum->Next(1, &var, &lFetch);
} //End While
}
}
}
hr=E_FAIL;
if (spDeploySite!=NULL)
{
CComBSTR bstrWebsitePath;
spDeploySite->get_ADsPath(&bstrWebsitePath);
bstrWebsitePath+=L"/ROOT";
CComPtr<IADs> spSite;
hr=ADsGetObject(bstrWebsitePath, IID_IADs, (void**) &spSite);
if (SUCCEEDED(hr))
{
CComVariant varPath;
spSite->Get(L"Path",&varPath);
strPath = V_BSTR(&varPath);
strPath += L"//";
}
}
return hr;
}