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; }
/*---------------------------------------------------------------------- * * 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; }
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; }