static int Main(string[] args) { int Result = 0; bool HasExclusive = false; // First and second arguments string Drive = null, ISOImage = null; MsftDiscMaster2Class DiscMaster = new MsftDiscMaster2Class(); MsftDiscRecorder2Class DiscRecorder = null; DDiscFormat2DataEvents_UpdateEventHandler EventHandler = new DDiscFormat2DataEvents_UpdateEventHandler(DiscFormatData_Update); #if DEBUG Drive = "D:\\"; ISOImage = @"C:\Users\manue\Desktop\Windows x64.iso"; #endif // Check arguments if no parameters already set if (string.IsNullOrEmpty(Drive) == true && string.IsNullOrEmpty(ISOImage) == true && args.Length < 2) { Log("Usage: ISOBurn <DrivePath> <ISOImage>"); Log("\tISOBurn e: d:\\summerpics.iso"); Result = ERR_INVALID_ARGS; goto Exit; } if (string.IsNullOrEmpty(Drive) == true) { Drive = args[0]; } if (string.IsNullOrEmpty(ISOImage) == true) { ISOImage = args[1]; } // If the file doesn't exist, waste no more time if (!System.IO.File.Exists(ISOImage)) { Console.WriteLine("File not found: {0}", ISOImage); Result = ERR_FILE_NOT_FOUND; goto Exit; } //// Check registry for windows 10 cd burning enabled //// https://www.technipages.com/enable-disable-cd-burning-windows //// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-create-a-key-in-the-registry //Microsoft.Win32.RegistryKey oExplorerKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer"); //string sName = "NoCDBurning"; //if (oExplorerKey != null) //{ // oExplorerKey.SetValue(sName, 0); // oExplorerKey.Close(); //} // Find the corresponding disc recorder for the drive for (int i = 0; i < DiscMaster.Count; ++i) { MsftDiscRecorder2Class DR = new MsftDiscRecorder2Class(); DR.InitializeDiscRecorder(DiscMaster[i]); foreach (string s in DR.VolumePathNames) { // Indicate the drive letter the system is using and set the disc recorder if (s.StartsWith(Drive, StringComparison.CurrentCultureIgnoreCase)) { Log("Using drive {0} for burning from ID {1}", s, DiscMaster[i]); Drive = s; DiscRecorder = DR; break; } } } // If we didn't set DiscRecorder, then no drive was found if (DiscRecorder == null) { Log("The drive {0} to burn to was not found.", Drive); Result = ERR_DRIVE_NOT_FOUND; goto Exit; } // Ensure the drive supports writing. List <IMAPI_FEATURE_PAGE_TYPE> Features = new List <IMAPI_FEATURE_PAGE_TYPE>(); foreach (IMAPI_FEATURE_PAGE_TYPE IFPT in DiscRecorder.SupportedFeaturePages) { Features.Add(IFPT); } // Is there a better way to do this? Doesn't look like a bitfield based on the enums (saddened) if (!Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_BD_WRITE) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_CD_RW_MEDIA_WRITE_SUPPORT) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_CDRW_CAV_WRITE) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_DOUBLE_DENSITY_CD_R_WRITE) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_DOUBLE_DENSITY_CD_RW_WRITE) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_DVD_DASH_WRITE) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_DVD_PLUS_R) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_DVD_PLUS_R_DUAL_LAYER) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_DVD_PLUS_RW) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_HD_DVD_WRITE) && !Features.Contains(IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_CD_MASTERING)) { Log("The drive {0} does not appear to support writing.", Drive); Result = ERR_DRIVE_NOT_SUPPORTED; goto Exit; } // Check to see if another application is already using the media and if so bail MsftDiscFormat2DataClass DiscFormatData = null; if (DiscRecorder.ExclusiveAccessOwner != null && DiscRecorder.ExclusiveAccessOwner.Length != 0) { Log("The drive {0} is in use by the application: {1}", Drive, DiscRecorder.ExclusiveAccessOwner); Result = ERR_DRIVE_IN_USE; goto Exit; } // Try to get exclusive access. This is important. In Vista 5728, Media Player causes this to return E_FAIL // even if it is just playing music in the background. try { DiscRecorder.AcquireExclusiveAccess(false, "ISOBurn Commandline Tool"); } catch (System.Exception e) { Log("Failed to acquire exclusive access to the burner: Message: {0}\nStack Trace: {1}", e.Message, e.StackTrace); Result = ERR_DRIVE_FAILED_ACQUIRE; goto Exit; } // Disable media change notifications so we don't have anyone else being notified that I'm doing stuff on the drive DiscRecorder.DisableMcn(); // Indicate we have exclusive access. HasExclusive = true; // Get the disk format which will hopefully let us know if we can write to the disk safely. Result = GetDiskFormatData(DiscRecorder, Drive, out DiscFormatData); if (Result != 0) { goto Exit; } // I would like to get the amount of free space on the media and compare that against the file size, but I'm not sure // if the file size of the ISO represents the raw sectors that would be written or whether it might be more tightly // packed. Also there might be additional sectors written on the disk to identify the image, etc that isn't // represented in the ISO. These are details I don't know to make this a little bit more robust. // Get the image to write IMAPI2.IStream Stream = null; int Res = SHCreateStreamOnFile(ISOImage, 0x20, out Stream); if (Res < 0) { Log("Opening the source ISO image {0} failed with error: {1}", ISOImage, Res); Result = Res; goto Exit; } // Set the client name DiscFormatData.ClientName = "ISOBurn Commandline Tool"; // Add the event handler *WHICH CURRENTLY DOES GENERATE EVENTS* DiscFormatData.Update += EventHandler; Log("Disk write speed is {0} sectors/second", DiscFormatData.CurrentWriteSpeed); // Write the stream try { DiscFormatData.Write(Stream); Log("Burn complete of {0} to {1}!", ISOImage, Drive); } catch (System.Exception e) { Log("Burn Failed: {0}\n{1}", e.Message, e.StackTrace.ToString()); goto Exit; } Exit: // Cleanup if (DiscRecorder != null && HasExclusive) { DiscRecorder.EnableMcn(); DiscRecorder.ReleaseExclusiveAccess(); DiscRecorder.EjectMedia(); } return(Result); }
static extern int SHCreateStreamOnFile(string pszFile, uint grfMode, out IMAPI2.IStream ppstm);