/************************************************************************ Copyright (c) 2002 Microsoft Corporation Module Name : config.cpp Abstract : Configuration APIs Author : Revision History : ***********************************************************************/ #include "precomp.h" #pragma warning( disable : 4355 ) WCHAR * ConvertObjectPathToADSI( const WCHAR *ObjectPath ) { WCHAR * ReturnPath = NULL; SIZE_T ReturnPathSize = 0; if ( _wcsnicmp( L"IIS://", (WCHAR*)ObjectPath, wcslen( L"IIS://") ) == 0 ) { // already have an adsi path ReturnPathSize = wcslen( ObjectPath ) + 1; ReturnPath = new WCHAR[ ReturnPathSize ]; if ( !ReturnPath ) throw ComError( E_OUTOFMEMORY ); memcpy( ReturnPath, ObjectPath, ReturnPathSize * sizeof( WCHAR ) ); } else if ( _wcsnicmp( L"/LM/", (WCHAR*)ObjectPath, wcslen( L"/LM/" ) ) == 0 ) { //metabase path to local machine ReturnPathSize = wcslen( (WCHAR*)ObjectPath ) + wcslen( L"IIS://LocalHost/" ) + 1; ReturnPath = new WCHAR[ ReturnPathSize ]; if ( !ReturnPath ) throw ComError( E_OUTOFMEMORY ); StringCchCopyW( ReturnPath, ReturnPathSize, L"IIS://LocalHost/" ); StringCchCatW( ReturnPath, ReturnPathSize, ObjectPath + wcslen( L"/LM/" ) ); } else if ( _wcsnicmp( L"LM/", (WCHAR*)ObjectPath, wcslen( L"LM/" ) ) == 0 ) { //metabase path to local machine ReturnPathSize = wcslen( (WCHAR*)ObjectPath ) + wcslen( L"IIS://LocalHost/" ) + 1; ReturnPath = new WCHAR[ ReturnPathSize ]; if ( !ReturnPath ) throw ComError( E_OUTOFMEMORY ); StringCchCopyW( ReturnPath, ReturnPathSize, L"IIS://LocalHost/" ); StringCchCatW( ReturnPath, ReturnPathSize, ObjectPath + wcslen( L"LM/" ) ); } else { //metabase path to another server ReturnPathSize = wcslen( (WCHAR*)ObjectPath ) + wcslen( L"IIS://" ) + 1; ReturnPath = new WCHAR[ ReturnPathSize ]; if ( !ReturnPath ) throw ComError( E_OUTOFMEMORY ); if ( '/' == *(WCHAR*)ObjectPath ) StringCchCopyW( ReturnPath, ReturnPathSize, L"IIS:/" ); else StringCchCopyW( ReturnPath, ReturnPathSize, L"IIS://" ); StringCchCatW( ReturnPath, ReturnPathSize, (WCHAR*)ObjectPath ); } return ReturnPath; } HRESULT GetTypeInfo( const GUID & guid, ITypeInfo **TypeInfo ) { DWORD Result; HRESULT hr; WCHAR DllName[ MAX_PATH ]; Result = GetModuleFileName( g_hinst, DllName, MAX_PATH - 1 ); if ( !Result ) return HRESULT_FROM_WIN32( GetLastError() ); ITypeLib *TypeLib; hr = LoadTypeLibEx( DllName, REGKIND_NONE, &TypeLib ); if ( FAILED( hr ) ) return hr; hr = TypeLib->GetTypeInfoOfGuid( guid, TypeInfo ); TypeLib->Release(); return hr; } void FreeReturnedWorkItems( ULONG NamesReturned, LPWSTR **ItemNamesPtr ) { LPWSTR *ItemNames = *ItemNamesPtr; if ( ItemNames ) { for( ULONG i = 0; i < NamesReturned; i++ ) { CoTaskMemFree( ItemNames[i] ); } CoTaskMemFree( ItemNames ); *ItemNamesPtr = NULL; } } HRESULT FindWorkItemForVDIR( ITaskScheduler *TaskScheduler, LPCWSTR Key, ITask **ReturnedTask, LPWSTR *ReturnedTaskName ) { HRESULT Hr; SIZE_T KeyLength = sizeof(WCHAR) * ( wcslen( Key ) + 1 ); WORD DataLength; if ( ReturnedTask ) *ReturnedTask = NULL; if ( ReturnedTaskName ) *ReturnedTaskName = NULL; ITask *Task = NULL; IEnumWorkItems *EnumWorkItems = NULL; LPWSTR *ItemNames = NULL; BYTE *ItemData = NULL; ULONG NamesReturned = 0; try { THROW_COMERROR( TaskScheduler->Enum( &EnumWorkItems ) ); while( 1 ) { THROW_COMERROR( EnumWorkItems->Next( 255, &ItemNames, &NamesReturned ) ); if ( !NamesReturned ) throw ComError( HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) ); for ( ULONG i = 0; i < NamesReturned; i++ ) { THROW_COMERROR( TaskScheduler->Activate( ItemNames[i], __uuidof( *Task ), (IUnknown**)&Task ) ); THROW_COMERROR( Task->GetWorkItemData( &DataLength, &ItemData ) ); if ( KeyLength == DataLength && ( wcscmp( Key, (WCHAR*)ItemData ) == 0 ) ) { // Found the item, cleanup and return if ( ReturnedTask ) *ReturnedTask = Task; else Task->Release(); if ( ReturnedTaskName ) { *ReturnedTaskName = ItemNames[i]; ItemNames[i] = NULL; } FreeReturnedWorkItems( NamesReturned, &ItemNames ); EnumWorkItems->Release(); CoTaskMemFree( ItemData ); return S_OK; } Task->Release(); Task = NULL; CoTaskMemFree( ItemData ); ItemData = NULL; } FreeReturnedWorkItems( NamesReturned, &ItemNames ); NamesReturned = 0; } } catch( ComError Error ) { if ( EnumWorkItems ) EnumWorkItems->Release(); if ( Task ) Task->Release(); FreeReturnedWorkItems( NamesReturned, &ItemNames ); CoTaskMemFree( ItemData ); return Error.m_Hr; } } HRESULT CreateWorkItemForVDIR( ITaskScheduler *TaskScheduler, LPCWSTR Path, LPCWSTR Key ) { WORD KeySize = sizeof(WCHAR) * ( wcslen( Key ) + 1 ); WCHAR ItemNameFormat[ MAX_PATH ]; WCHAR ItemName[ MAX_PATH * 4 ]; WCHAR Parameters[ MAX_PATH * 4]; LoadString( g_hinst, IDS_WORK_ITEM_NAME, ItemNameFormat, MAX_PATH - 1 ); // Use the last part of the path for the description const WCHAR *ShortPath = Path + wcslen( Path ); while( *ShortPath != L'/' && *ShortPath != L'\\' && ShortPath != Path ) ShortPath--; if ( *ShortPath == L'/' || *ShortPath == L'\\' ) ShortPath++; DWORD Result; void* InsertArray[2] = { (void*)ShortPath, (void*)Key }; Result = FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, (LPCVOID)ItemNameFormat, 0, 0, ItemName, MAX_PATH * 4, (va_list*)InsertArray ); if ( !Result ) return HRESULT_FROM_WIN32( GetLastError() ); StringCbPrintfW( Parameters, sizeof( Parameters ), L"bitsmgr.dll,Cleanup_RunDLL %s \"%s\" %s", Path, ItemName, Key ); WORD TriggerNumber; ITask *Task = NULL; ITaskTrigger *TaskTrigger = NULL; IPersistFile *PersistFile = NULL; try { HRESULT Hr; Hr = FindWorkItemForVDIR( TaskScheduler, Key, &Task, NULL ); if ( SUCCEEDED( Hr ) ) { // The work item already exists Task->Release(); return S_OK; } if ( FAILED(Hr) && HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) != Hr ) THROW_COMERROR( Hr ); THROW_COMERROR( TaskScheduler->NewWorkItem( ItemName, CLSID_CTask, __uuidof( *Task ), (IUnknown**)&Task ) ); // Set basic task data THROW_COMERROR( Task->SetApplicationName( L"%SystemRoot%\\system32\\rundll32.exe" ) ); THROW_COMERROR( Task->SetMaxRunTime( INFINITE ) ); THROW_COMERROR( Task->SetParameters( Parameters ) ); THROW_COMERROR( Task->SetPriority( IDLE_PRIORITY_CLASS ) ); THROW_COMERROR( Task->SetAccountInformation( L"", NULL ) ); //Run as localsystem THROW_COMERROR( Task->SetFlags( TASK_FLAG_RUN_ONLY_IF_LOGGED_ON | TASK_FLAG_HIDDEN ) ); THROW_COMERROR( Task->SetWorkItemData( KeySize, (BYTE*)Key ) ); // set trigger information. Set start time to now, with a default // interval of once a day. THROW_COMERROR( Task->CreateTrigger( &TriggerNumber, &TaskTrigger ) ); SYSTEMTIME LocalTime; GetLocalTime( &LocalTime ); TASK_TRIGGER Trigger; memset( &Trigger, 0, sizeof( Trigger ) ); Trigger.cbTriggerSize = sizeof(Trigger); Trigger.wBeginYear = LocalTime.wYear; Trigger.wBeginMonth = LocalTime.wMonth; Trigger.wBeginDay = LocalTime.wDay; Trigger.wStartHour = LocalTime.wHour; Trigger.wStartMinute = LocalTime.wMinute; Trigger.TriggerType = TASK_TIME_TRIGGER_DAILY; Trigger.MinutesDuration = 24 * 60; // 24 hours per day Trigger.MinutesInterval = 12 * 60; // twice per day Trigger.Type.Daily.DaysInterval = 1; THROW_COMERROR( TaskTrigger->SetTrigger( &Trigger ) ); // Commit the changes to disk. THROW_COMERROR( Task->QueryInterface( __uuidof( IPersistFile ), (void**)&PersistFile ) ); THROW_COMERROR( PersistFile->Save( NULL, TRUE ) ); PersistFile->Release(); TaskTrigger->Release(); Task->Release(); return S_OK; } catch( ComError Error ) { if ( TaskTrigger ) TaskTrigger->Release(); if ( Task ) Task->Release(); if ( PersistFile ) PersistFile->Release(); TaskScheduler->Delete( ItemName ); return Error.m_Hr; } } HRESULT DeleteWorkItemForVDIR( ITaskScheduler *TaskScheduler, LPWSTR Key ) { HRESULT Hr; LPWSTR TaskName = NULL; Hr = FindWorkItemForVDIR( TaskScheduler, Key, NULL, &TaskName ); if ( HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) == Hr ) return S_OK; if ( FAILED( Hr ) ) return Hr; Hr = TaskScheduler->Delete( TaskName ); CoTaskMemFree( TaskName ); return Hr; } HRESULT ConnectToTaskScheduler( LPWSTR ComputerName, ITaskScheduler ** TaskScheduler ) { HRESULT Hr; Hr = CoCreateInstance( CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, __uuidof( **TaskScheduler ), (void **) TaskScheduler ); if ( FAILED( Hr ) ) return Hr; Hr = (*TaskScheduler)->SetTargetComputer( ComputerName ); if ( FAILED( Hr ) ) { (*TaskScheduler)->Release(); (*TaskScheduler) = NULL; return Hr; } return S_OK; } HRESULT IsBITSEnabledOnVDir( PropertyIDManager *PropertyManager, IMSAdminBase *IISAdminBase, LPWSTR VirtualDirectory, BOOL *IsEnabled ) { HRESULT Hr; DWORD BufferRequired; *IsEnabled = false; DWORD IsEnabledVal; METADATA_RECORD MdRecord; memset( &MdRecord, 0, sizeof( MdRecord ) ); MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ); MdRecord.dwMDDataLen = sizeof(IsEnabled); MdRecord.pbMDData = (PBYTE)&IsEnabledVal; Hr = IISAdminBase->GetData( METADATA_MASTER_ROOT_HANDLE, VirtualDirectory, &MdRecord, &BufferRequired ); if ( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) return S_OK; if ( FAILED( Hr ) ) return Hr; *IsEnabled = IsEnabledVal ? true : false; return S_OK; } HRESULT EnableBITSForVDIR( PropertyIDManager *PropertyManager, IMSAdminBase *IISAdminBase, LPCWSTR Path ) { HRESULT Hr; METADATA_HANDLE MdVDirKey = NULL; LPWSTR NewScriptMapBuffer = NULL; ITaskScheduler* TaskScheduler = NULL; try { Hr = DisableBITSForVDIR( PropertyManager, IISAdminBase, Path, true ); if ( FAILED( Hr ) ) throw ComError( Hr ); // build the string to add to the scriptmap WCHAR SystemDir[ MAX_PATH + 1 ]; if (!GetSystemDirectoryW( SystemDir, MAX_PATH ) ) throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); WCHAR ScriptMapString[ MAX_PATH * 2 + 1 ]; StringCbPrintfW( ScriptMapString, sizeof( ScriptMapString ), L"*,%s\\bitssrv.dll,1," BITS_COMMAND_VERBW, SystemDir ); int RetChars = wcslen( ScriptMapString ); ScriptMapString[ RetChars ] = L'\0'; ScriptMapString[ RetChars + 1] = L'\0'; RetChars += 2; // ScriptMapScript is now double NULL terminated Hr = IISAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, Path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 30000, &MdVDirKey ); if (FAILED(Hr)) throw ComError(Hr); DWORD IsEnabled; DWORD BufferRequired; METADATA_RECORD MdRecord; DWORD AccessFlags; MdRecord.dwMDIdentifier = MD_ACCESS_PERM; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDDataLen = sizeof( AccessFlags ); MdRecord.pbMDData = (unsigned char*)&AccessFlags; MdRecord.dwMDDataTag = 0; Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ); if ( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) { AccessFlags = 0; } else if ( FAILED( Hr ) ) { throw ComError( Hr ); } if ( AccessFlags & ( MD_ACCESS_SCRIPT | MD_ACCESS_EXECUTE ) ) { AccessFlags &= ~( MD_ACCESS_SCRIPT | MD_ACCESS_EXECUTE ); MdRecord.dwMDAttributes &= ~METADATA_ISINHERITED; Hr = IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ); if ( FAILED( Hr ) ) throw ComError( Hr ); } MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ); MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDUserType = ALL_METADATA; MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDDataLen = sizeof(IsEnabled); MdRecord.pbMDData = (PBYTE)&IsEnabled; MdRecord.dwMDDataTag = 0; Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ); if ( FAILED( Hr ) ) { if ( !( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) ) { IISAdminBase->CloseKey( MdVDirKey ); return S_OK; } } else if ( IsEnabled ) { IISAdminBase->CloseKey( MdVDirKey ); return S_OK; } // // retrieve the current scriptmap adding room to the allocated memory // memset( &MdRecord, 0, sizeof( MdRecord ) ); MdRecord.dwMDDataType = MULTISZ_METADATA; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDIdentifier = MD_SCRIPT_MAPS; MdRecord.dwMDDataLen = 0; MdRecord.pbMDData = (PBYTE)NULL; Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ); if ( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) { // The Current key doesn't exist. MdRecord.pbMDData = (PBYTE)ScriptMapString; MdRecord.dwMDDataLen = RetChars * sizeof(WCHAR); } else if ( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) == Hr ) { NewScriptMapBuffer = new WCHAR[ ( BufferRequired / sizeof(WCHAR) ) + RetChars ]; MdRecord.pbMDData = (PBYTE)NewScriptMapBuffer; MdRecord.dwMDDataLen = BufferRequired + ( RetChars * sizeof(WCHAR) ); Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ); if ( FAILED(Hr) ) throw ComError( Hr ); // append script entry at the end for( WCHAR *p = NewScriptMapBuffer; *p != 0; p += ( wcslen( p ) + 1 ) ); memcpy( p, ScriptMapString, RetChars * sizeof(WCHAR) ); MdRecord.pbMDData = (PBYTE)NewScriptMapBuffer; MdRecord.dwMDDataLen = (DWORD)( ( (char*)p - (char*)NewScriptMapBuffer ) + ( RetChars * sizeof(WCHAR) ) ); } else throw ComError( Hr ); // Write out the new values starting with ScriptMap Hr = IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ); if ( FAILED( Hr ) ) throw ComError( Hr ); // Set the enabled property DWORD EnableData = 1; memset( &MdRecord, 0, sizeof( MdRecord ) ); MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_UPLOAD_ENABLED ); MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ); MdRecord.dwMDDataLen = sizeof(EnableData); MdRecord.pbMDData = (PBYTE)&EnableData; Hr = IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ); if ( FAILED( Hr ) ) throw ComError( Hr ); delete[] NewScriptMapBuffer; // Create the task scheduler cleanup work item WCHAR GuidString[ 255 ]; // first try looking up the guid MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDDataLen = sizeof( GuidString ); MdRecord.pbMDData = (PBYTE)GuidString; MdRecord.dwMDDataTag = 0; Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ); if ( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) { // create a new guid and save it away GUID guid; THROW_COMERROR( CoCreateGuid( &guid ) ); StringFromGUID2( guid, GuidString, 254 ); MdRecord.dwMDDataLen = sizeof(WCHAR) * ( wcslen(GuidString) + 1 ); MdRecord.pbMDData = (PBYTE)GuidString; THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ) ); } else if ( FAILED( Hr ) ) throw ComError( Hr ); THROW_COMERROR( ConnectToTaskScheduler( NULL, &TaskScheduler ) ); THROW_COMERROR( CreateWorkItemForVDIR( TaskScheduler, Path, GuidString ) ); TaskScheduler->Release(); IISAdminBase->CloseKey( MdVDirKey ); return S_OK; } catch( ComError Exception ) { if ( TaskScheduler ) TaskScheduler->Release(); DisableBITSForVDIR( PropertyManager, IISAdminBase, Path, false ); delete[] NewScriptMapBuffer; if ( MdVDirKey ) IISAdminBase->CloseKey( MdVDirKey ); return Exception.m_Hr; } } HRESULT DisableBITSForVDIR( PropertyIDManager *PropertyManager, IMSAdminBase *IISAdminBase, LPCWSTR Path, bool DisableForEnable ) { HRESULT Hr; METADATA_HANDLE MdVDirKey = NULL; LPWSTR OriginalScriptMap = NULL; LPWSTR NewScriptMap = NULL; ITaskScheduler* TaskScheduler = NULL; try { if ( !DisableForEnable ) CleanupForRemoval( Path ); // build the string to add to the scriptmap WCHAR SystemDir[ MAX_PATH + 1 ]; if (!GetSystemDirectoryW( SystemDir, MAX_PATH ) ) throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); WCHAR ScriptMapString[ MAX_PATH * 2 + 1 ]; StringCchPrintfW( ScriptMapString, MAX_PATH * 2 + 1, L"*,%s\\bitssrv.dll,1,BITS_COMMAND", SystemDir ); int RetChars = wcslen( ScriptMapString ); ScriptMapString[ RetChars ] = L'\0'; ScriptMapString[ RetChars + 1] = L'\0'; // ScriptMapScript is now double NULL terminated WCHAR ScriptMapString2[ MAX_PATH * 2 + 1]; StringCbPrintfW( ScriptMapString2, sizeof( ScriptMapString2 ), L"*,%\\bitsserver.dll,1,BITS_COMMAND", SystemDir ); RetChars = wcslen( ScriptMapString2 ); ScriptMapString2[ RetChars ] = L'\0'; ScriptMapString2[ RetChars + 1 ] = L'\0'; // ScriptMapScript2 is not double NULL terminated WCHAR ScriptMapString3[ MAX_PATH * 2 + 1 ]; StringCbPrintfW( ScriptMapString3, sizeof( ScriptMapString3 ), L"*,%s\\bitssrv.dll,1," BITS_COMMAND_VERBW, SystemDir ); RetChars = wcslen( ScriptMapString3 ); ScriptMapString3[ RetChars ] = L'\0'; ScriptMapString3[ RetChars + 1] = L'\0'; // ScriptMapScript3 is now double NULL terminated THROW_COMERROR( IISAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, Path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 30000, &MdVDirKey ) ); // // retrieve the current scriptmap adding room to the allocated memory // DWORD BufferRequired; METADATA_RECORD MdRecord; memset( &MdRecord, 0, sizeof( MdRecord ) ); MdRecord.dwMDDataType = MULTISZ_METADATA; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDIdentifier = MD_SCRIPT_MAPS; MdRecord.dwMDDataLen = 0; MdRecord.pbMDData = (PBYTE)NULL; Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ); if ( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) != Hr ) throw ComError( Hr ); OriginalScriptMap = new WCHAR[ BufferRequired / 2 + 2 ]; NewScriptMap = new WCHAR[ BufferRequired / 2 + 2 ]; OriginalScriptMap[0] = OriginalScriptMap[1] = L'\0'; MdRecord.dwMDDataLen = BufferRequired; MdRecord.pbMDData = (PBYTE)OriginalScriptMap; Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ); if ( FAILED(Hr) ) throw ComError( Hr ); // Copy the orignal Scriptmap to the new scriptmap // removing bits goo in the process. LPWSTR CurrentOriginalItem = OriginalScriptMap; LPWSTR CurrentNewItem = NewScriptMap; for( ;L'\0' != *CurrentOriginalItem; CurrentOriginalItem += ( wcslen( CurrentOriginalItem ) + 1 ) ) { if ( _wcsicmp( CurrentOriginalItem, ScriptMapString ) == 0 ) continue; //remove this item if ( _wcsicmp( CurrentOriginalItem, ScriptMapString2 ) == 0 ) continue; if ( _wcsicmp( CurrentOriginalItem, ScriptMapString3 ) == 0 ) continue; SIZE_T CurrentOriginalItemSize = wcslen( CurrentOriginalItem ) + 1; memcpy( CurrentNewItem, CurrentOriginalItem, CurrentOriginalItemSize * sizeof( WCHAR ) ); CurrentNewItem += CurrentOriginalItemSize; } // Add the extra 0 *CurrentNewItem++ = L'\0'; MdRecord.dwMDDataLen = (DWORD)( (char*)CurrentNewItem - (char*)NewScriptMap ); MdRecord.pbMDData = (PBYTE)NewScriptMap; // Set the is enabled property first DWORD EnableData = 0; METADATA_RECORD MdEnabledRecord; memset( &MdEnabledRecord, 0, sizeof( MdEnabledRecord ) ); MdEnabledRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdEnabledRecord.dwMDDataType = DWORD_METADATA; MdEnabledRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_UPLOAD_ENABLED ); MdEnabledRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ); MdEnabledRecord.dwMDDataLen = sizeof(EnableData); MdEnabledRecord.pbMDData = (PBYTE)&EnableData; Hr = IISAdminBase->SetData( MdVDirKey, NULL, &MdEnabledRecord ); if ( FAILED( Hr ) ) throw ComError( Hr ); // set the new scriptmap Hr = IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ); if ( FAILED( Hr ) ) throw ComError( Hr ); WCHAR GuidString[ 255 ]; memset( &MdRecord, 0, sizeof( MdRecord ) ); MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDDataLen = sizeof( GuidString ); MdRecord.pbMDData = (PBYTE)GuidString; Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ); if ( FAILED( Hr ) && Hr != MD_ERROR_DATA_NOT_FOUND ) throw ComError( Hr ); if ( SUCCEEDED( Hr ) && !DisableForEnable ) { THROW_COMERROR( ConnectToTaskScheduler( NULL, &TaskScheduler ) ); THROW_COMERROR( DeleteWorkItemForVDIR( TaskScheduler, GuidString ) ); TaskScheduler->Release(); THROW_COMERROR( IISAdminBase->DeleteData( MdVDirKey, NULL, PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ), ALL_METADATA ) ); } delete[] OriginalScriptMap; delete[] NewScriptMap; IISAdminBase->CloseKey( MdVDirKey ); MdVDirKey = NULL; return S_OK; } catch( ComError Exception ) { if ( TaskScheduler ) TaskScheduler->Release(); delete[] OriginalScriptMap; delete[] NewScriptMap; if ( MdVDirKey ) IISAdminBase->CloseKey( MdVDirKey ); return Exception.m_Hr; } } HRESULT FindWorkItemForVDIR( PropertyIDManager *PropertyManager, IMSAdminBase *AdminBase, LPCWSTR Path, LPWSTR *ReturnedTaskName ) { if ( ReturnedTaskName ) *ReturnedTaskName = NULL; WCHAR GuidString[ 255 ]; DWORD BufferRequired; METADATA_RECORD MdRecord; HRESULT Hr; MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDDataLen = sizeof( GuidString ); MdRecord.pbMDData = (PBYTE)GuidString; MdRecord.dwMDDataTag = 0; Hr = AdminBase->GetData( METADATA_MASTER_ROOT_HANDLE, Path, &MdRecord, &BufferRequired ); if ( MD_ERROR_DATA_NOT_FOUND == Hr ) return S_FALSE; ITaskScheduler* TaskScheduler = NULL; Hr = ConnectToTaskScheduler( NULL, &TaskScheduler ); if ( FAILED( Hr ) ) return Hr; Hr = FindWorkItemForVDIR( TaskScheduler, GuidString, NULL, ReturnedTaskName ); // simply return NULL if the task item isn't found. if ( HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) == Hr ) Hr = S_FALSE; TaskScheduler->Release(); return Hr; } CBITSExtensionSetupFactory::CBITSExtensionSetupFactory() : m_cref(1), m_TypeInfo(NULL) { OBJECT_CREATED } CBITSExtensionSetupFactory::~CBITSExtensionSetupFactory() { if ( m_TypeInfo ) m_TypeInfo->Release(); OBJECT_DESTROYED } STDMETHODIMP CBITSExtensionSetupFactory::QueryInterface(REFIID riid, LPVOID *ppv) { if (!ppv) return E_FAIL; *ppv = NULL; if (IsEqualIID(riid, IID_IUnknown)) *ppv = static_cast(this); else if (IsEqualIID(riid, __uuidof(IBITSExtensionSetupFactory))) *ppv = static_cast(this); if (*ppv) { reinterpret_cast(*ppv)->AddRef(); return S_OK; } return E_NOINTERFACE; } STDMETHODIMP_(ULONG) CBITSExtensionSetupFactory::AddRef() { return InterlockedIncrement((LONG *)&m_cref); } STDMETHODIMP_(ULONG) CBITSExtensionSetupFactory::Release() { if (InterlockedDecrement((LONG *)&m_cref) == 0) { // we need to decrement our object count in the DLL delete this; return 0; } return m_cref; } HRESULT CBITSExtensionSetupFactory::LoadTypeInfo() { if ( m_TypeInfo ) return S_OK; return ::GetTypeInfo( __uuidof( IBITSExtensionSetupFactory ), &m_TypeInfo ); } STDMETHODIMP CBITSExtensionSetupFactory::GetIDsOfNames( REFIID, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID, DISPID FAR* rgDispId ) { HRESULT Hr; Hr = LoadTypeInfo(); if ( FAILED( Hr ) ) return Hr; return DispGetIDsOfNames( m_TypeInfo, rgszNames, cNames, rgDispId); } STDMETHODIMP CBITSExtensionSetupFactory::GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) { *ppTInfo = NULL; if(iTInfo != 0) return ResultFromScode(DISP_E_BADINDEX); HRESULT Hr; Hr = LoadTypeInfo(); if ( FAILED( Hr ) ) return Hr; m_TypeInfo->AddRef(); *ppTInfo = m_TypeInfo; return NOERROR; } STDMETHODIMP CBITSExtensionSetupFactory::GetTypeInfoCount( unsigned int FAR* pctinfo ) { *pctinfo = 1; return NOERROR; } STDMETHODIMP CBITSExtensionSetupFactory::Invoke( DISPID dispIdMember, REFIID, LCID, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) { HRESULT Hr; Hr = LoadTypeInfo(); if ( FAILED( Hr ) ) return Hr; return DispInvoke( this, m_TypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } STDMETHODIMP CBITSExtensionSetupFactory::GetObject( BSTR Path, IBITSExtensionSetup **ppExtensionSetup ) { WCHAR *ObjectPath = NULL; IUnknown *Object = NULL; try { if ( !Path || !ppExtensionSetup ) throw ComError( E_INVALIDARG ); *ppExtensionSetup = NULL; ObjectPath = ConvertObjectPathToADSI( (WCHAR*)Path ); THROW_COMERROR( ADsGetObject( BSTR( ObjectPath ), __uuidof( IUnknown ), (void**)&Object ) ); delete ObjectPath; ObjectPath = NULL; CBITSExtensionSetup *SetupObj = new CBITSExtensionSetup( NULL, Object ); if ( !SetupObj ) throw ComError( E_OUTOFMEMORY ); Object = NULL; *ppExtensionSetup = static_cast( SetupObj ); return S_OK; } catch( ComError Error ) { delete ObjectPath; if ( Object ) Object->Release(); return Error.m_Hr; } } STDMETHODIMP CNonDelegatingIUnknown::QueryInterface(REFIID riid, LPVOID *ppv) { if (!ppv) return E_FAIL; *ppv = NULL; if ( riid == __uuidof(IUnknown) ) *ppv = static_cast(this); else if ( riid == __uuidof(IDispatch) ) *ppv = static_cast(m_DelegatingIUnknown); else if ( riid == __uuidof(IBITSExtensionSetup) ) *ppv = static_cast(m_DelegatingIUnknown); else if ( riid == __uuidof(IADsExtension) ) *ppv = static_cast(m_DelegatingIUnknown); if (*ppv) { reinterpret_cast(*ppv)->AddRef(); return S_OK; } return E_NOINTERFACE; } STDMETHODIMP_(ULONG) CNonDelegatingIUnknown::AddRef() { return InterlockedIncrement((LONG *)&m_cref); } STDMETHODIMP_(ULONG) CNonDelegatingIUnknown::Release() { if (InterlockedDecrement((LONG *)&m_cref) == 0) { // we need to decrement our object count in the DLL delete m_DelegatingIUnknown; return 0; } return m_cref; } CNonDelegatingIUnknown::CNonDelegatingIUnknown( CBITSExtensionSetup * DelegatingIUnknown ) : m_DelegatingIUnknown( DelegatingIUnknown ), m_cref(1) { } CBITSExtensionSetup::CBITSExtensionSetup( IUnknown *Outer, IUnknown *Object ) : m_pOuter( Outer ), m_pObject( Object ), m_OuterDispatch( NULL ), m_TypeInfo( NULL ), m_ADSIPath( NULL ), m_Path( NULL ), m_PropertyMan( NULL ), m_DelegationIUnknown( this ), m_RemoteInterface( NULL ), m_InitComplete( false ), m_Lock( 0 ) { if ( m_pOuter ) { HRESULT Hr = m_pOuter->QueryInterface( __uuidof( IDispatch ), (void**)&m_OuterDispatch ); if ( FAILED( Hr ) ) m_OuterDispatch = NULL; } OBJECT_CREATED } CBITSExtensionSetup::~CBITSExtensionSetup() { if ( m_pObject ) { m_pObject->Release(); m_pObject = NULL; } if ( m_OuterDispatch ) m_OuterDispatch->Release(); if ( m_TypeInfo ) m_TypeInfo->Release(); delete[] m_Path; // Noop on NULL m_Path = NULL; if ( m_RemoteInterface ) m_RemoteInterface->Release(); delete m_PropertyMan; SysFreeString( m_ADSIPath ); OBJECT_DESTROYED } STDMETHODIMP CBITSExtensionSetup::QueryInterface(REFIID riid, LPVOID *ppv) { if ( m_pOuter ) return m_pOuter->QueryInterface( riid, ppv ); else return m_DelegationIUnknown.QueryInterface( riid, ppv ); } STDMETHODIMP_(ULONG) CBITSExtensionSetup::AddRef() { if ( m_pOuter ) return m_pOuter->AddRef(); else return m_DelegationIUnknown.AddRef(); } STDMETHODIMP_(ULONG) CBITSExtensionSetup::Release() { if ( m_pOuter ) return m_pOuter->AddRef(); else return m_DelegationIUnknown.AddRef(); } HRESULT CBITSExtensionSetup::LoadTypeInfo() { if ( m_TypeInfo ) return S_OK; // Lock object while( InterlockedExchange( &m_Lock, 1 ) ) Sleep( 0 ); HRESULT Hr = ::GetTypeInfo( __uuidof( IBITSExtensionSetup ), &m_TypeInfo ); // Unlock the object InterlockedExchange( &m_Lock, 0 ); return Hr; } STDMETHODIMP CBITSExtensionSetup::Operate( ULONG dwCode, VARIANT varData1, VARIANT varData2, VARIANT varData3) { return E_NOTIMPL; } STDMETHODIMP CBITSExtensionSetup::PrivateGetIDsOfNames( REFIID, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID, DISPID FAR* rgDispId ) { HRESULT Hr; Hr = LoadTypeInfo(); if ( FAILED( Hr ) ) return Hr; return DispGetIDsOfNames( m_TypeInfo, rgszNames, cNames, rgDispId); } STDMETHODIMP CBITSExtensionSetup::PrivateGetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) { *ppTInfo = NULL; if(iTInfo != 0) return ResultFromScode(DISP_E_BADINDEX); HRESULT Hr; Hr = LoadTypeInfo(); if ( FAILED( Hr ) ) return Hr; m_TypeInfo->AddRef(); *ppTInfo = m_TypeInfo; return NOERROR; } STDMETHODIMP CBITSExtensionSetup::PrivateGetTypeInfoCount( unsigned int FAR* pctinfo ) { *pctinfo = 1; return NOERROR; } STDMETHODIMP CBITSExtensionSetup::PrivateInvoke( DISPID dispIdMember, REFIID, LCID, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) { HRESULT Hr; Hr = LoadTypeInfo(); if ( FAILED( Hr ) ) return Hr; return DispInvoke( static_cast(this), m_TypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } STDMETHODIMP CBITSExtensionSetup::GetIDsOfNames( REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId ) { if ( m_OuterDispatch ) return m_OuterDispatch->GetIDsOfNames( riid, rgszNames, cNames, lcid, rgDispId ); return PrivateGetIDsOfNames( riid, rgszNames, cNames, lcid, rgDispId ); } STDMETHODIMP CBITSExtensionSetup::GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) { if ( m_OuterDispatch ) return m_OuterDispatch->GetTypeInfo( iTInfo, lcid, ppTInfo ); return PrivateGetTypeInfo( iTInfo, lcid, ppTInfo ); } STDMETHODIMP CBITSExtensionSetup::GetTypeInfoCount( unsigned int FAR* pctinfo ) { if ( m_OuterDispatch ) return m_OuterDispatch->GetTypeInfoCount( pctinfo ); return PrivateGetTypeInfoCount( pctinfo ); } STDMETHODIMP CBITSExtensionSetup::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) { if ( m_OuterDispatch ) return m_OuterDispatch->Invoke( dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr ); return PrivateInvoke( dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr ); } HRESULT CBITSExtensionSetup::ConnectToRemoteExtension() { WCHAR *HostName = NULL; WCHAR *NewPath = NULL; BSTR NewPathBSTR = NULL; IBITSExtensionSetupFactory* Factory = NULL; try { // Extract out the host part of the path const SIZE_T PrefixSize = sizeof(L"IIS://")/sizeof(WCHAR) - 1; if ( _wcsnicmp( (WCHAR*)m_ADSIPath, L"IIS://", PrefixSize ) != 0 ) throw ComError( E_INVALIDARG ); WCHAR *HostNameStart = ((WCHAR*)m_ADSIPath) + PrefixSize; WCHAR *p = HostNameStart; while( L'/' != *p ) { if ( L'\0' == *p ) throw ComError( E_INVALIDARG ); p++; } SIZE_T HostNameSize = (char*)p - (char*)HostNameStart + sizeof(L'\0'); HostName = new WCHAR[ HostNameSize / sizeof(WCHAR) ]; if ( !HostName ) throw ComError( E_OUTOFMEMORY ); memcpy( HostName, HostNameStart, HostNameSize - sizeof(WCHAR) ); HostName[ ( HostNameSize - sizeof(WCHAR) ) / sizeof(WCHAR) ] = L'\0'; if ( L'\0' == *++p ) throw ComError( E_INVALIDARG ); SIZE_T NewPathSize = wcslen( L"IIS://LocalHost/" ) + wcslen( p ) + 1; NewPath = new WCHAR[ NewPathSize ]; if ( !NewPath ) throw ComError( E_OUTOFMEMORY ); StringCchCopyW( NewPath, NewPathSize, L"IIS://LocalHost/" ); StringCchCatW( NewPath, NewPathSize, p ); NewPathBSTR = SysAllocString( NewPath ); if ( !NewPathBSTR ) throw ComError( E_OUTOFMEMORY ); COSERVERINFO coinfo; coinfo.dwReserved1 = 0; coinfo.dwReserved2 = 0; coinfo.pAuthInfo = NULL; coinfo.pwszName = HostName; GUID guid = __uuidof( IBITSExtensionSetupFactory ); MULTI_QI mqi; mqi.hr = S_OK; mqi.pIID = &guid; mqi.pItf = NULL; THROW_COMERROR( CoCreateInstanceEx( __uuidof(BITSExtensionSetupFactory), NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, &coinfo, 1, &mqi ) ); THROW_COMERROR( mqi.hr ); Factory = (IBITSExtensionSetupFactory*)mqi.pItf; mqi.pItf = NULL; THROW_COMERROR( Factory->GetObject( NewPathBSTR, &m_RemoteInterface ) ); Factory->Release(); SysFreeString( NewPathBSTR ); delete[] NewPath; delete[] HostName; return S_OK; } catch( ComError Error ) { SysFreeString( NewPathBSTR ); delete[] HostName; delete[] NewPath; if ( Factory ) Factory->Release(); return Error.m_Hr; } } HRESULT CBITSExtensionSetup::LoadPath() { HRESULT Hr; if ( m_InitComplete ) return S_OK; // Lock object while( InterlockedExchange( &m_Lock, 1 ) ) Sleep( 0 ); if ( !m_PropertyMan ) { m_PropertyMan = new PropertyIDManager(); if ( !m_PropertyMan ) { Hr = E_OUTOFMEMORY; goto error; } Hr = m_PropertyMan->LoadPropertyInfo(); if ( FAILED(Hr) ) { delete m_PropertyMan; m_PropertyMan = NULL; goto error; } } if ( !m_ADSIPath ) { IADs *ObjectADS = NULL; if ( m_pObject ) Hr = m_pObject->QueryInterface( __uuidof(*ObjectADS), (void**) &ObjectADS ); else Hr = m_pOuter->QueryInterface( __uuidof(*ObjectADS), (void**) &ObjectADS ); if ( FAILED( Hr ) ) goto error; Hr = ObjectADS->get_ADsPath( &m_ADSIPath ); ObjectADS->Release(); ObjectADS = NULL; if ( FAILED( Hr ) ) goto error; } if ( !m_Path && !m_RemoteInterface ) { if ( _wcsnicmp( (WCHAR*)m_ADSIPath, L"IIS://LocalHost/", wcslen( L"IIS://LocalHost/" ) ) == 0 ) { SIZE_T PathSize = wcslen( (WCHAR*)m_ADSIPath ) + 1; m_Path = new WCHAR[ PathSize ]; if ( !m_Path ) { Hr = E_OUTOFMEMORY; goto error; } StringCchCopyW( m_Path, PathSize, L"/LM/" ); StringCchCatW( m_Path, PathSize, reinterpret_cast( m_ADSIPath ) + wcslen( L"IIS://LocalHost/" ) ); } else { Hr = ConnectToRemoteExtension( ); if ( FAILED( Hr ) ) goto error; } } m_InitComplete = true; // unlock InterlockedExchange( &m_Lock, 0 ); return S_OK; error: // unlock InterlockedExchange( &m_Lock, 0 ); return Hr; } STDMETHODIMP CBITSExtensionSetup::EnableBITSUploads() { HRESULT Hr = LoadPath(); if ( FAILED(Hr) ) return Hr; if ( m_RemoteInterface ) return m_RemoteInterface->EnableBITSUploads(); IMSAdminBase *AdminBase = NULL; Hr = CoCreateInstance( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_SERVER, __uuidof( IMSAdminBase ), (LPVOID*)&AdminBase ); if ( FAILED( Hr ) ) return Hr; Hr = EnableBITSForVDIR( m_PropertyMan, AdminBase, m_Path ); AdminBase->Release(); return Hr; } STDMETHODIMP CBITSExtensionSetup::DisableBITSUploads() { HRESULT Hr = LoadPath(); if ( FAILED(Hr) ) return Hr; if ( m_RemoteInterface ) return m_RemoteInterface->DisableBITSUploads(); IMSAdminBase *AdminBase = NULL; Hr = CoCreateInstance( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_SERVER, __uuidof( IMSAdminBase ), (LPVOID*)&AdminBase ); if ( FAILED( Hr ) ) return Hr; Hr = DisableBITSForVDIR( m_PropertyMan, AdminBase, m_Path, false ); AdminBase->Release(); return Hr; } STDMETHODIMP CBITSExtensionSetup::GetCleanupTaskName( BSTR *pTaskName ) { *pTaskName = NULL; HRESULT Hr = LoadPath(); if ( FAILED(Hr) ) return Hr; if ( m_RemoteInterface ) return m_RemoteInterface->GetCleanupTaskName( pTaskName ); IMSAdminBase *AdminBase = NULL; Hr = CoCreateInstance( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_SERVER, __uuidof( IMSAdminBase ), (LPVOID*)&AdminBase ); if ( FAILED( Hr ) ) return Hr; LPWSTR TaskName = NULL; Hr = FindWorkItemForVDIR( m_PropertyMan, AdminBase, m_Path, &TaskName ); if ( SUCCEEDED( Hr ) && TaskName ) { *pTaskName = SysAllocString( TaskName ); if ( !*pTaskName ) Hr = E_OUTOFMEMORY; CoTaskMemFree( TaskName ); TaskName = NULL; } AdminBase->Release(); return Hr; } STDMETHODIMP CBITSExtensionSetup::GetCleanupTask( [in] REFIID riid, [out,retval] IUnknown **ppUnk ) { HRESULT Hr = S_OK; ITaskScheduler *TaskScheduler = NULL; BSTR ItemName = NULL; WCHAR *HostName = NULL; if ( ppUnk ) *ppUnk = NULL; try { THROW_COMERROR( LoadPath() ); // // Build the taskscheduler form of the host name // const SIZE_T PrefixSize = sizeof(L"IIS://")/sizeof(WCHAR) - 1; if ( _wcsnicmp( (WCHAR*)m_ADSIPath, L"IIS://", PrefixSize ) != 0 ) throw ComError( E_INVALIDARG ); WCHAR *HostNameStart = ((WCHAR*)m_ADSIPath) + PrefixSize; WCHAR *p = HostNameStart; while( L'/' != *p ) { if ( L'\0' == *p ) throw ComError( E_INVALIDARG ); p++; } SIZE_T HostNameSize = (char*)p - (char*)HostNameStart + sizeof(L'\0'); HostName = new WCHAR[ ( HostNameSize / sizeof(WCHAR) ) + 2 ]; if ( !HostName ) throw ComError( E_OUTOFMEMORY ); HostName[0] = HostName[1] = L'\\'; memcpy( HostName + 2, HostNameStart, HostNameSize - sizeof(WCHAR) ); HostName[ ( ( HostNameSize - sizeof(WCHAR) ) / sizeof(WCHAR) ) + 2 ] = L'\0'; if ( _wcsicmp( HostName, L"\\\\LocalHost" ) == 0 ) { delete[] HostName; HostName = NULL; } THROW_COMERROR( ConnectToTaskScheduler( HostName, &TaskScheduler ) ); THROW_COMERROR( GetCleanupTaskName( &ItemName ) ); if ( ItemName ) THROW_COMERROR( TaskScheduler->Activate( (LPCWSTR)ItemName, riid, ppUnk ) ); else Hr = S_FALSE; } catch( ComError Error ) { Hr = Error.m_Hr; } if ( TaskScheduler ) TaskScheduler->Release(); SysFreeString( ItemName ); delete[] HostName; return Hr; } #include "bitssrvcfgimp.h"