HRESULT CMsftEraseSample::EraseByWrite(IMAPI_MEDIA_PHYSICAL_TYPE mediaType)
{
    HRESULT             hr = S_OK;
    IStream*            firstStream = NULL;
    IStream*            secondStream = NULL;
    IWriteEngine2*      writeEngine = NULL;
    PDISC_INFORMATION   discInfo = NULL;
    ULONG               discInfoSize = 0;
    LONG                totalSectorsToWrite = 0;

    // 0) For DVD+RW media, check if never formatted
    if (mediaType == IMAPI_MEDIA_TYPE_DVDPLUSRW)
    {
        if (SUCCEEDED (hr)) 
        {
            ULONG requiredSize = RTL_SIZEOF_THROUGH_FIELD (DISC_INFORMATION, 
                                                           FirstTrackNumber);
            hr = GetDiscInformation (m_RecorderEx, &discInfo, &discInfoSize, requiredSize);
        }

        if (SUCCEEDED(hr))
        {
            //    0.1) Exit early if media is totally blank and unused for both
            //         quick and full formats.
            if (discInfo->DiscStatus == 0)
            {                
                hr = S_OK;
                goto EraseByWriteExit;
            }
        }
    }

    // 1) Determine the size of the media
    if (SUCCEEDED(hr))
    {
        ULONG bytesPerBlock = 0;
        ULONG userSectors = 0;

        hr = ReadMediaCapacity(m_RecorderEx, &bytesPerBlock, &userSectors);
        totalSectorsToWrite = userSectors;
    }

    // For a quick erase on DVD+RW media we need to write over the first 2MB of the media
    // and the last 2MB of formatted media, not the last 2MB of total media.  
    // Currently do not have a way to determine this so will do two writes over the beginning of the media.
    // In the event there is less than 2mb of formatted media, the drive will format
    // the entire media, which we do not want.
    if (SUCCEEDED(hr))
    {
        if ((mediaType == IMAPI_MEDIA_TYPE_DVDPLUSRW) && (!m_FullErase))
        {
            // This will take us into our pathological case below
            totalSectorsToWrite = DefaultSectorsPerWriteForQuickErase;
        }
    }

    // 2) Determine the size of the first write
    //    2.1) For quick-erase, always 2MB
    //    2.2) For full erase, capacity of media minus 2MB
    if (SUCCEEDED(hr))
    {
        if (totalSectorsToWrite < (2*DefaultSectorsPerWriteForQuickErase))
        {
            // pathological case 
            m_SectorsFirstWrite = totalSectorsToWrite;
            m_SectorsSecondWrite = totalSectorsToWrite;
        }
        else if (m_FullErase)
        {
            m_SectorsFirstWrite = totalSectorsToWrite - DefaultSectorsPerWriteForQuickErase;
            m_SectorsSecondWrite = DefaultSectorsPerWriteForQuickErase;
        }
        else
        {
            m_SectorsFirstWrite = DefaultSectorsPerWriteForQuickErase;
            m_SectorsSecondWrite = DefaultSectorsPerWriteForQuickErase;
        }
    }

    // 3) Create two MsftStreamZero objects
    if (SUCCEEDED(hr))
    {
        hr = CoCreateInstance(CLSID_MsftStreamZero,
                              NULL, CLSCTX_ALL,
                              IID_PPV_ARGS(&firstStream)
                              );
        if (SUCCEEDED(hr))
        {
            hr = CoCreateInstance(CLSID_MsftStreamZero,
                                  NULL, CLSCTX_ALL,
                                  IID_PPV_ARGS(&secondStream)
                                  );
        }
    }
    //    3.1) First one is size of first write
    if (SUCCEEDED(hr))
    {
        ULARGE_INTEGER newSize; 
        RtlZeroMemory(&newSize, sizeof(ULARGE_INTEGER));
        newSize.QuadPart = ((ULONGLONG)2048) * m_SectorsFirstWrite;
        hr = firstStream->SetSize(newSize);
    }
    //    3.2) Second one is always 2MB
    if (SUCCEEDED(hr))
    {
        ULARGE_INTEGER newSize; 
        RtlZeroMemory(&newSize, sizeof(ULARGE_INTEGER));
        newSize.QuadPart = ((ULONGLONG)2048) * m_SectorsSecondWrite;
        hr = secondStream->SetSize(newSize);
    }

    // 4) Setup write engine
    //    4.1) Setup write engine
    {
        // Create a WriteEngine
        if (SUCCEEDED(hr))
        {
            hr = CoCreateInstance(CLSID_MsftWriteEngine2,
                                  NULL, CLSCTX_ALL,
                                  IID_PPV_ARGS(&writeEngine)
                                  );
        }
        // set the disc recorder and options for the write engine
        if (SUCCEEDED(hr))
        {
            hr = writeEngine->put_Recorder(m_RecorderEx);
        }
        // NOT UseStreamingWrite12
        if (SUCCEEDED(hr))
        {
            hr = writeEngine->put_UseStreamingWrite12(VARIANT_FALSE);
        }
        // StartingBlocksPerSecond
        if (SUCCEEDED(hr))
        {
            hr = writeEngine->put_StartingSectorsPerSecond(75*40); // 40x CD, 4x DVD
        }
        // EndingBlocksPerSecond
        if (SUCCEEDED(hr))
        {
            hr = writeEngine->put_EndingSectorsPerSecond(75*40); // 40x CD, 4x DVD
        }
        // BytesPerBlock
        if (SUCCEEDED(hr))
        {
            hr = writeEngine->put_BytesPerSector(2048);
        }
    }
    //    4.2) initialize event information
    // connect the events for the write engine
    if (SUCCEEDED(hr))
    {
        hr = EraseWriteEngineEventSimpleImpl::DispEventAdvise(writeEngine, &IID_DWriteEngine2Events);
    }

    //    4.3) Create the required timekeeping objects
    if (SUCCEEDED(hr))
    {
        ULONG expectedMilliseconds = MILLISECONDS_FROM_SECONDS(15);
        m_TimeKeeperWrite = new CTaskTimeEstimator(expectedMilliseconds, m_SectorsFirstWrite + m_SectorsSecondWrite);
        if (m_TimeKeeperWrite == NULL)
        {
            hr = E_OUTOFMEMORY;
        }
    }

    // Set the drive's OPC
    if (SUCCEEDED(hr))
    {
        hr = RequestAutomaticOPC(m_RecorderEx);
        if (FAILED(hr))
        {
            hr = S_OK;
        }
    }

    // 5) Write the data (zeros)
    if (SUCCEEDED(hr))
    {
        m_TimeKeeperWrite->StartNow();
    }

    //    5.1) Write the first section
    // Ask write engine to write  (/dev/zero stream)
    if (SUCCEEDED(hr))
    {
        m_WritingFirstSection = TRUE;

        // start LBA == 0
        hr = writeEngine->WriteSection(firstStream, 0, m_SectorsFirstWrite);
    }

    //    5.2) Write the second section
    // Ask write engine to write  (/dev/zero stream)
    if (SUCCEEDED(hr))
    {
        m_WritingFirstSection = FALSE;
        // start LBA == totalSectorsToWrite - m_SectorsSecondWrite; 

        hr = writeEngine->WriteSection(secondStream, totalSectorsToWrite - m_SectorsSecondWrite, m_SectorsSecondWrite);
    }
    m_TimeKeeperWrite->EndNow();

    // 6) Finalize the media as required (per-media routines)
    if (SUCCEEDED(hr))
    {
        hr = SendSynchronizeCacheCommand(m_RecorderEx, SYNCHRONIZE_CACHE_TIMEOUT, FALSE);
    }


EraseByWriteExit:
    // CLEANUP FOLLOWS ///////////////////////////////
    delete m_TimeKeeperWrite; 
    m_TimeKeeperWrite = NULL; // delete of NULL is harmless
    CoTaskMemFreeAndNull(discInfo);
    ReleaseAndNull(firstStream);
    ReleaseAndNull(secondStream);
    ReleaseAndNull(writeEngine);

    return hr;
}
BOOLEAN CMsftEraseSample::CheckRecorderSupportsErase(__in IDiscRecorder2Ex* DiscRecorder, BOOLEAN CheckCurrentMedia)
{
    PFEATURE_DATA_INCREMENTAL_STREAMING_WRITABLE incrementalStreaming = NULL;
    ULONG                                       incrementalStreamingSize = 0;
    PFEATURE_DATA_RESTRICTED_OVERWRITE          restrictedOverwrite = NULL;
    ULONG                                       restrictedOverwriteSize = 0;
    PFEATURE_DATA_CD_TRACK_AT_ONCE              cdTao = NULL;
    ULONG                                       cdTaoSize = 0;
    PFEATURE_DATA_DVD_RW_RESTRICTED_OVERWRITE   rigidOverwrite = NULL;
    ULONG                                       rigidOverwriteSize = 0;
    PFEATURE_DATA_DVD_RECORDABLE_WRITE          dvdDash = NULL;
    ULONG                                       dvdDashSize = 0;
    PFEATURE_DATA_DDCD_RW_WRITE                 ddCdrwWrite = NULL;
    ULONG                                       ddCdrwWriteSize = 0;
    PCDVD_CAPABILITIES_PAGE                     capabilities;
    ULONG                                       capabilitiesSize;
    HRESULT                                     hr = S_OK;
    ULONG                                       requiredSize = 0;
    BOOLEAN                                     supported = FALSE;

    DiscRecorder->GetFeaturePage (
        IMAPI_FEATURE_PAGE_TYPE_INCREMENTAL_STREAMING_WRITABLE,
        FALSE,
        (BYTE**)&incrementalStreaming,
        &incrementalStreamingSize);
   
    DiscRecorder->GetFeaturePage (
        IMAPI_FEATURE_PAGE_TYPE_RESTRICTED_OVERWRITE,
        FALSE,
        (BYTE**)&restrictedOverwrite,
        &restrictedOverwriteSize);

    DiscRecorder->GetFeaturePage (
        IMAPI_FEATURE_PAGE_TYPE_CD_TRACK_AT_ONCE,
        FALSE,
        (BYTE**)&cdTao,
        &cdTaoSize);

    DiscRecorder->GetFeaturePage (
        IMAPI_FEATURE_PAGE_TYPE_RIGID_RESTRICTED_OVERWRITE,
        FALSE,
        (BYTE**)&rigidOverwrite,
        &rigidOverwriteSize);

    DiscRecorder->GetFeaturePage (
        IMAPI_FEATURE_PAGE_TYPE_DVD_DASH_WRITE,
        FALSE,
        (BYTE**)&dvdDash,
        &dvdDashSize);
    
    DiscRecorder->GetFeaturePage (
        IMAPI_FEATURE_PAGE_TYPE_DOUBLE_DENSITY_CD_RW_WRITE,
        FALSE,
        (BYTE**)&ddCdrwWrite,
        &ddCdrwWriteSize);

    //
    // The recorder is supported if any of the following is true:
    // incremental streaming write requires blank
    // restricted overwrite requires blank
    // cdtao requires blank
    // rigid restricted overwrite requires blank if blank bit set
    // DVD-R/-RW requires blank if DVD-RW bit set
    // DDCD-RW feature requires blank if blank bit set
    //

    if ((incrementalStreaming != NULL) && 
        (incrementalStreaming->Header.Current || !CheckCurrentMedia))
    {
        supported = TRUE;
    }
        
    if ((restrictedOverwrite != NULL) &&
        (restrictedOverwrite->Header.Current || !CheckCurrentMedia)) 
    {
        supported = TRUE;
    }

    if ((cdTao != NULL) && 
        (cdTao->Header.Current || !CheckCurrentMedia))
    {
        supported = TRUE;
    }
    
    if ((rigidOverwrite != NULL) &&
        (rigidOverwrite->Header.Current || !CheckCurrentMedia) &&
        (rigidOverwriteSize >= 8) &&
        (rigidOverwrite->Blank != 0)) 
    {
        supported = TRUE;
    }

    if ((dvdDash != NULL) &&
        (dvdDash->Header.Current || !CheckCurrentMedia) &&
        (dvdDashSize >= 8) &&
        (dvdDash->DVD_RW != 0)) 
    {
        supported = TRUE;
    }

    if ((ddCdrwWrite != NULL) &&
        (ddCdrwWrite->Header.Current || !CheckCurrentMedia) &&
        (ddCdrwWriteSize >= 8) &&
        (ddCdrwWrite->Blank != 0)) 
    {
        supported = TRUE;
    }

    //
    // some older CD-R/RW drives didn't support GET_CONFIGURATION
    //

    if (!supported) 
    {
        capabilities = NULL;
        capabilitiesSize = 0;
        
        //
        // if none of the features are available, it's possible we may
        // still need to support this device if it's a cd recorder according
        // to mode page 2Ah.
        //

        requiredSize = RTL_SIZEOF_THROUGH_FIELD (CDVD_CAPABILITIES_PAGE,
                                                 NumberVolumeLevels);

        
        hr = GetDiscCapabilities (DiscRecorder,
                                  &capabilities, 
                                  &capabilitiesSize,
                                  requiredSize);
        
        if (SUCCEEDED (hr)) 
        {
            assert (capabilities != NULL);
            assert (capabilitiesSize >=8);
            
            if (capabilities->CDEWrite) 
            {
                supported = TRUE;
            }
            
            CoTaskMemFreeAndNull (capabilities);
        }
    }
    
    CoTaskMemFreeAndNull (ddCdrwWrite);
    CoTaskMemFreeAndNull (dvdDash);
    CoTaskMemFreeAndNull (rigidOverwrite);
    CoTaskMemFreeAndNull (cdTao);
    CoTaskMemFreeAndNull (restrictedOverwrite);
    CoTaskMemFreeAndNull (incrementalStreaming);

    return supported;
}
Beispiel #3
0
/*----------------------------------------------------------------------
 *
 * IOCTL routines. All routines use buffered I/O.
 *
 */
static NTSTATUS CfixkrsQueryModuleIoctl(
	__in PVOID Buffer,
	__in ULONG InputBufferLength,
	__in ULONG OutputBufferLength,
	__out PULONG BytesWritten
	)
{
	ULONG BufferSize;
	PCFIXKRP_DRIVER_CONNECTION DriverConnection;
	PCFIXKR_IOCTL_QUERY_TEST_MODULE_REQUEST Request;
	PCFIXKR_IOCTL_QUERY_TEST_MODULE_RESPONSE Response;
	NTSTATUS Status;

	ASSERT( BytesWritten );

	*BytesWritten = 0;

	//
	// Validate parameters.
	//
	if ( ! Buffer ||
		 InputBufferLength != sizeof( CFIXKR_IOCTL_QUERY_TEST_MODULE_REQUEST ) ||
		 OutputBufferLength < RTL_SIZEOF_THROUGH_FIELD( 
			CFIXKR_IOCTL_QUERY_TEST_MODULE_RESPONSE, u.SizeRequired ) )
	{
		return STATUS_INVALID_PARAMETER;
	}

	Request = ( PCFIXKR_IOCTL_QUERY_TEST_MODULE_REQUEST ) Buffer;
	Response = ( PCFIXKR_IOCTL_QUERY_TEST_MODULE_RESPONSE ) Buffer;

	//
	// Try to lookup connection to this driver.
	//
	Status = CfixkrpLookupDriverConnection(
		Request->DriverBaseAddress,
		&DriverConnection );
	if ( ! NT_SUCCESS( Status ) )
	{
		return Status;
	}

	//
	// Fill buffer - if it is large enough.
	//
	Status = CfixkrpQueryModuleDriverConnection(
		DriverConnection,
		OutputBufferLength,
		Buffer,
		&BufferSize );

	if ( Status == STATUS_BUFFER_OVERFLOW )
	{
		//
		// BufferSize contains necessary size.
		//
		Response->u.SizeRequired = BufferSize;
		*BytesWritten = RTL_SIZEOF_THROUGH_FIELD( 
			CFIXKR_IOCTL_QUERY_TEST_MODULE_RESPONSE, u.SizeRequired );
	}
	else if ( NT_SUCCESS( Status ) )
	{
		//
		// Buffer has been filled.
		//
		*BytesWritten = BufferSize;
	}
	else
	{
		//
		// Some error occurred.
		//
	}

	CfixkrpDereferenceConnection( DriverConnection );

	ASSERT( *BytesWritten <= OutputBufferLength );

	return Status;
}
STDMETHODIMP CMsftEraseSample::IsCurrentMediaSupported(IDiscRecorder2* Recorder, VARIANT_BOOL* Supported)
{
    IDiscRecorder2Ex*   tmpRecorderEx = NULL;
    BOOLEAN             tmpSupported = FALSE;
    HRESULT             hr = S_OK;
    PDISC_INFORMATION   discInfo = NULL;
    ULONG               discInfoSize = 0;
    ULONG               requiredSize;

    if (Recorder == NULL) 
    {
        hr = E_POINTER;
    }

    if (Supported == NULL) 
    {
        hr = E_POINTER;
    } 
    else 
    {
        *Supported = VARIANT_FALSE;
    }

    // get a pointer to the IDR2Ex interface as well
    if (SUCCEEDED(hr))
    {
        hr = Recorder->QueryInterface(IID_PPV_ARGS(&tmpRecorderEx));
    }

    if (SUCCEEDED (hr)) 
    {
        tmpSupported = CheckRecorderSupportsErase(tmpRecorderEx, TRUE);
    }

    //
    // If it's supported, and they are asking about the current media,
    // need to check that the disc is actually erasable via READ_DISC_INFO
    //
        
    if (SUCCEEDED (hr) && (tmpSupported)) 
    {
        tmpSupported = FALSE;

        requiredSize = RTL_SIZEOF_THROUGH_FIELD (DISC_INFORMATION, 
                                                 FirstTrackNumber);

        hr = GetDiscInformation (tmpRecorderEx, &discInfo, &discInfoSize, requiredSize);

        if (SUCCEEDED (hr)) 
        {
            assert (discInfo != NULL);
            assert (discInfoSize >= 12);

            if (discInfo->Erasable) 
            {
                tmpSupported = TRUE;
            }

            CoTaskMemFreeAndNull( discInfo );
        }
    }

    if (SUCCEEDED(hr)) 
    {
        *Supported = tmpSupported ? VARIANT_TRUE : VARIANT_FALSE;
    }

    // release the temporary IDiscRecorder2Ex
    ReleaseAndNull(tmpRecorderEx);
    return hr;

}
Beispiel #5
0
static NTSTATUS CfixkrsGetModulesIoctl(
	__in PVOID Buffer,
	__in ULONG InputBufferLength,
	__in ULONG OutputBufferLength,
	__out PULONG BytesWritten
	)
{
	ULONG Capacity;
	ULONG ElementsWritten;
	ULONG ElementsAvailable;
	PCFIXKR_IOCTL_GET_MODULES Response;
	NTSTATUS Status;

	ASSERT( BytesWritten );

	*BytesWritten = 0;

	//
	// Validate parameters.
	//
	if ( ! Buffer ||
		 InputBufferLength != 0 ||
		 OutputBufferLength < sizeof( CFIXKR_IOCTL_GET_MODULES ) )
	{
		return STATUS_INVALID_PARAMETER;
	}

	//
	// Calculate how many elements the output buffer can hold.
	//
	Capacity = ( OutputBufferLength - 
		FIELD_OFFSET( CFIXKR_IOCTL_GET_MODULES, DriverLoadAddress ) ) /
		sizeof( ULONGLONG );
	Response = ( PCFIXKR_IOCTL_GET_MODULES ) Buffer;
	
	ASSERT( Capacity >= 1 );

	Status = CfixkrpGetDriverConnections(
		Capacity,
		Response->DriverLoadAddress,
		&ElementsWritten,
		&ElementsAvailable );
	if ( Status == STATUS_BUFFER_OVERFLOW )
	{
		Response->Count = ElementsAvailable;
		*BytesWritten = RTL_SIZEOF_THROUGH_FIELD( 
			CFIXKR_IOCTL_GET_MODULES, 
			DriverLoadAddress[ ElementsWritten - 1 ] );
	}
	else if ( NT_SUCCESS( Status ) )
	{
		Response->Count = ElementsWritten;
		if ( ElementsWritten == 0 )
		{
			*BytesWritten = RTL_SIZEOF_THROUGH_FIELD( 
				CFIXKR_IOCTL_GET_MODULES, 
				Count );
		}
		else
		{
			*BytesWritten = RTL_SIZEOF_THROUGH_FIELD( 
				CFIXKR_IOCTL_GET_MODULES, 
				DriverLoadAddress[ ElementsWritten - 1 ] );
		}
	}
	else
	{
		//
		// Some error occurred.
		//
	}

	ASSERT( *BytesWritten <= OutputBufferLength );

	return Status;
}