[Tutorial] CDs Brennen mit C# und Nero API

alexander
Hi,

guenni81 hat sich die Mühe gemacht und ein Tutorial geschrieben, welches beschreibt wie man mit Hilfe von C# sowie NeroAPI CDs brennen kann.

Also viel Spaß beim Lesen und nochmal vielen Dank an guenni81.
EtiketteTötet
Dank auch von mir an guenni81
Gumble
Super Tutorial Daumen hoch
Gibts eigentlich ausser dem pdf, das bei dem NeroCom SDK dabei ist noch eine Beschreibung der Bibliothek? Bitte kein VB - davon hab ich null Ahnung. Will naemlich um die (RCW) gewrappte Library eine einfache .NET-Komponente basteln - d.h. nur die Funktionen anbieten die ich brauche. Noch leider blick ichs noch net ganz. Da steckt einfach zuviel Funktionalitaet drin.
Beispiele waeren auch klasse. Habe hier leider keinen Brenner eingebaut, deswegen wuerd ich gern mit dem Image-Recorder testen. Ich brauch doch nur den Haendler hinzufuegen und dort den string mit dem Target-path+name zu ueberschreiben?

C#-Code:
neroClass.OnFileSelImage += new NEROLib._INeroEvents_OnFileSelImageEventHandler(OnFileSelImage);

Gibts einen globalen Fehlerhandler? Hab irgendwie kein passendes Event gefunden. Welche Events sollte man denn alle behandeln?
Gibts eine Funktion um ein Verzeichnis + alle Unterverzeichnisse inkl. Inhalt einer NeroFolderClass zu adden? Oder muss ich (muehsam) mich durch alles durchhangeln und jedes File einzeln adden?

Danke schonmal fuer Hilfe smile
guenni81
@Gumble
Es gibt leider soweit ich damals gefunden habe nur sehr wenige informationen zu der NeroAPI. Wenn du Informationen unter google suchst, bekommst du meist VB anwendung/beispiele. Es ist schon ziemlich lange her das ich das letzte mal etwas in C# gemacht habe. Das einzigste was dir bleibt ist suchen. Für das problem mit dem Pfad und den Dateien adden könntest du dir ja ne eigene Funktion schreiben wenn es wirklich nix geben sollte.
Gumble
Also ich habe mich jetzt noch weiter damit auseinander gesetzt - es klappt zwar schon ganz gut, aber sehr transparent ist das alles nicht. Ab und an krieg ich Fehler aufgrund 2 asynchroner Operations - passiert beim debuggen nicht - abhilfe durch (halb)aktives warten und statusvariable: habe vor und nach dem BurnIsoAudioCD-Aufruf eine solche Schleife um den internen hochprioren NeroThread genuegend Zeit zum werkeln zu geben:
while(longOperation == true)
{
Thread.Sleep(500);
Console.WriteLine("locked");
}
die longOperation variable entsperre ich in den EventHandlermethoden OnDoneBurn und nDrive_OnDoneEstimateTrackSize.
Ich glaube mein Design ist grausam smile
Jedenfalls klappt es nicht mehr wenn ich anstelle der Consolenausgabe (z.B. in OnProgress - Methode) den aktuellen Status in einem Form visualisiere (beinhaltet eine Progressbar). Schon allein das halten einer Instanz [edit: nein, war zu uebereifrig - siehe Beitrag spaeter] veranlasst den Nerothread keine Events mehr zu senden so dass ich natuerlich auch nie aus meiner Speerschleife rauskomme. Verstehen tu ichs nicht.
Wems interessiert, kann ich den Code ja gezippt zukommen lassen, oder ich stell ihn hier rein. Muss ihn aber erstmal bisschen saeubern smile Ziel meines Vorhabens: eine schlanke .NET dll mit der man mit einem einzigen static Aufruf einfach eine cd/dvd brennen kann - so nach der Art Burn(string label, string folder, string imagePath, string recorder, int speed, string cdtype).
yahoo
Hallo Gumble (+Co)!

Wär echt super, wenn du dein Projekt mal hochladen könntest
und die URL posten, oder wenn du mir es kurz
an michijaroAThotmailDOTcom
mailst.

Vielen Dank,

Yahoo
Gumble
das Ganze Projekt lade ich lieber nicht hoch - nerocom wie in der Anleitung selber wrappen! geht ganz einfach. Hier der Code. Das Progressform ist ein einfaches Windows.Forms.Form mit einem Label und einer Bar.

C#-Code:
using System;
using System.IO;
using System.Collections;
using System.Threading;
using System.Drawing;
using System.Windows.Forms;
using NEROLib;

namespace CDServices_NET
{
    public delegate void OnProgressDelegate (int ProgressInPercent, string phase);

    public class CDService: System.Windows.Forms.Form
    {
        #region Attributes
        private NeroClass nClass;
        private NeroFolder nRootFolder;
        private NeroDrive nDrive;
        private NeroDrives nDrives;
        private NeroISOTrack nISOTrack;
        private string artist = "";
        private string title = "";
        private string imageTarget = @"c:\image.iso";
        private NERO_MEDIA_TYPE nType = 0;
        private int burningSpeed;
        private bool longOperation = false;
        private string phase = "";
        private ProgressForm myProgressForm = new ProgressForm();
        # endregion

        #region Events
        public event OnProgressDelegate OnNeroProgress;
        #endregion

        # region Properties
        public string Artist
        {
            get
            {
                return artist;
            }
            set
            {
                artist = value;
            }
        }

        public string Title
        {
            get
            {
                return title;
            }
            set
            {
                title = value;
            }
        }

        public string ImageTarget
        {
            get
            {
                return imageTarget;
            }
            set
            {
                imageTarget = @value;
            }
        }
        # endregion

        #region Contructors
        public CDService()
        {
            nClass = new NeroClass();
            nRootFolder = new NeroFolderClass();
            nISOTrack = new NeroISOTrackClass();
        }
        #endregion

        # region static Methods
        public static void StaticBurn( string title, string imageTarget, string path, string recorder, int burningSpeed, string mediaType)
        {
            NERO_MEDIA_TYPE nType = (NERO_MEDIA_TYPE) Enum.Parse(typeof(NERO_MEDIA_TYPE), mediaType, true);
            CDService cd = new CDService();
            cd.SelectRecoder(recorder);
            cd.ImageTarget = imageTarget;
            cd.Title = title;
            cd.AddAllToFolderRecursive(new DirectoryInfo(@path));
            cd.nISOTrack.Name = cd.Title;
            cd.Burn(burningSpeed, nType);
        }

        public static void StaticBurn( string title, string path, string recorder, int burningSpeed, string mediaType)
        {
            StaticBurn (title, @"c:\image.iso", path, recorder, burningSpeed, mediaType);
        }
        # endregion

        #region Methods

        public void Burn ( string title, string imageTarget, string path, string recorder, int burningSpeed, string mediaType)
        {
            Title = title;
            ImageTarget = imageTarget;
            AddAllToFolderRecursive(new DirectoryInfo(@path));
            SelectRecoder(recorder);
            Burn(burningSpeed);
        }

        public void Burn(int burningSpeed)
        {
            Burn(burningSpeed, NERO_MEDIA_TYPE.NERO_MEDIA_NONE);
        }

        public void Burn(int speed, NERO_MEDIA_TYPE mediaType)
        {
            if (nDrive == null)
                throw new Exception("no recorder selected");
            myProgressForm.totalNumber = 100;
            myProgressForm.Show();
            nISOTrack.RootFolder = nRootFolder;
            burningSpeed = speed;
            nType = mediaType;


            longOperation = true;
            nDrive.EstimateTrackSize(nISOTrack, NERO_ESTIMATE_FLAGS.NETS_DATA, null);


            //adding handler    
            nDrive.OnDoneBurn += new _INeroDriveEvents_OnDoneBurnEventHandler(OnDoneBurn);
            nDrive.OnProgress += new _INeroDriveEvents_OnProgressEventHandler(OnProgress);
            nDrive.OnDoneWaitForMedia += new _INeroDriveEvents_OnDoneWaitForMediaEventHandler(nDrive_OnDoneWaitForMedia);
            nDrive.OnAddLogLine += new _INeroDriveEvents_OnAddLogLineEventHandler(nDrive_OnAddLogLine);
            nDrive.OnSetPhase += new _INeroDriveEvents_OnSetPhaseEventHandler(nDrive_OnSetPhase);
            nDrive.OnAborted += new _INeroDriveEvents_OnAbortedEventHandler(nDrive_OnAborted);
            nDrive.OnDoneCDInfo +=new _INeroDriveEvents_OnDoneCDInfoEventHandler(nDrive_OnDoneCDInfo);
            nDrive.OnDoneEstimateTrackSize +=new _INeroDriveEvents_OnDoneEstimateTrackSizeEventHandler(nDrive_OnDoneEstimateTrackSize);
            nDrive.OnDoneImport += new _INeroDriveEvents_OnDoneImportEventHandler(nDrive_OnDoneImport);

            nClass.OnFileSelImage += new _INeroEvents_OnFileSelImageEventHandler(OnFileSelImage);
            nClass.OnMegaFatal += new _INeroEvents_OnMegaFatalEventHandler(nClass_OnMegaFatal);
            nClass.OnNonEmptyCDRW += new _INeroEvents_OnNonEmptyCDRWEventHandler(nClass_OnNonEmptyCDRW);
            nClass.OnWaitCD += new _INeroEvents_OnWaitCDEventHandler(nClass_OnWaitCD);
            nClass.OnWaitCDMediaInfo += new _INeroEvents_OnWaitCDMediaInfoEventHandler(nClass_OnWaitCDMediaInfo);
            nClass.OnWaitCDReminder += new _INeroEvents_OnWaitCDReminderEventHandler(nClass_OnWaitCDReminder);
            nClass.OnWaitCDDone += new _INeroEvents_OnWaitCDDoneEventHandler(nClass_OnWaitCDDone);
            nClass.OnDriveStatusChanged +=new _INeroEvents_OnDriveStatusChangedEventHandler(nClass_OnDriveStatusChanged);


            while(longOperation == true)
            {
                Thread.Sleep(500);
                Console.WriteLine("locked");
            }
            longOperation = true;

            nDrive.BurnIsoAudioCD(Artist, Title, false, nISOTrack, null, null, NERO_BURN_FLAGS.NERO_BURN_FLAG_WRITE,
                burningSpeed, nType);

            while(longOperation == true)
            {
                Thread.Sleep(500);
                Console.WriteLine("locked");
            }


        }

        private ArrayList GetRecoderList(NERO_MEDIA_TYPE property)
        {
            nType = property;
            ArrayList al = new ArrayList();

            nDrives = (NeroDrives)nClass.GetDrives(property);

            foreach(NeroDrive nd in nDrives)
            {
                al.Add(nd.DeviceName);
            }
            return al;
        }

        public void SelectRecoder(string recoderName)
        {
            nDrives = (NeroDrivesClass)nClass.GetDrives(nType);
            foreach(NeroDrive nd in nDrives)
            {
                if (nd.DeviceName == recoderName)
                {
                    nDrive = nd;
                    return;
                }
            }

            throw new Exception("cannot find selected target with Name: " + recoderName);
        }

        public void SelectRecoder(int  recoderID)
        {
            foreach(NeroDrive nd in nDrives)
            {
                if (nd.DeviceID == recoderID)
                {
                    nDrive = nd;
                    return;
                }
            }
            throw new Exception("cannot find selected target with ID: " + recoderID);
        }

        public void AddAllToFolderRecursive(DirectoryInfo rootDir)
        {
            AddAllToFolderRecursive(nRootFolder, rootDir);
        }

        private void AddAllToFolderRecursive( NeroFolder rootFolder, DirectoryInfo rootDir)
        {
            foreach (FileInfo fi in rootDir.GetFiles())
            {
                NeroFile newFile = new NeroFileClass();
                newFile.Name = fi.Name;
                newFile.SourceFilePath = fi.FullName;
                rootFolder.Files.Add(newFile);
            }
            foreach (DirectoryInfo di in rootDir.GetDirectories())
            {
                NeroFolder newFolder = new NeroFolderClass();
                newFolder.Name = di.Name;
                rootFolder.Folders.Add(newFolder);
                AddAllToFolderRecursive(newFolder, di);
            }

        }


        //Here we present the user with the results of the burn process
        private void OnDoneBurn(ref NERO_BURN_ERROR statusCode)
        {
            longOperation = false;
            if (statusCode != NERO_BURN_ERROR.NERO_BURN_OK)
                Console.WriteLine("OnDoneBurn: NOT successful! " + statusCode + " " + nClass.ErrorLog.ToString() + nClass.LastError.ToString());
            else
                Console.WriteLine("OnDoneBurn: successful! " + statusCode);

        }

        //Here we just want to display the text that NeroCOM offers us whenever a line is
        //added to the log.
        private void nDrive_OnAddLogLine(ref NERO_TEXT_TYPE TextType, ref string Text)
        {
            Console.WriteLine("nDrive_OnAddLogLine: " + TextType + " : " + Text);
        }

        //OnAborted queries whether an operation shall be aborted. We always return
        //false; if we choose to abort, we will explicitly call the Nero object’s abort method.
        private void nDrive_OnAborted(ref bool Abort)
        {
            Abort = false;
        }

        //progress reports from NeroCOM.
        private void OnProgress(ref int ProgressInPercent, ref bool Abort)
        {
            Abort = false;
            if (OnNeroProgress != null)
                OnNeroProgress(ProgressInPercent, this.phase);

            Console.WriteLine("OnProgress: " + ProgressInPercent);
            myProgressForm.currentNumber = ProgressInPercent;
            //myProgressForm.Invalidate();
        }

        //This event will be called when Nero has stopped waiting for the media.
        private void nDrive_OnDoneWaitForMedia(ref bool Success)
        {
            Console.WriteLine("nDrive_OnDoneWaitForMedia: ");
        }

        //finding out about the current phase NeroCOM is in –
        //writing data, writing lead-in or lead-out parts of the CD-ROM and related information.
        private void nDrive_OnSetPhase(ref string Text)
        {
            this.phase = Text;
            Console.WriteLine("nDrive_OnSetPhase: " + Text);
        }


        //This handler is called when a very critical error occurs.
        private void nClass_OnMegaFatal()
        {
            Console.WriteLine("nClass_OnMegaFatal: " + "A mega fatal error has occurred.");
        }

        //If the user decides to use the virtual device and not a real device more
        //information is needed. The data that NeroCOM creates will be written to an
        //image file. To provide the location of that file we need to handle this event.
        private void OnFileSelImage(ref string target)
        {
            target = ImageTarget;
            Console.WriteLine("OnFileSelImage: " + target);
        }

        //This event will be called whenever the user tries to write on a non-empty CD-RW.
        //We merely return NERO_RETURN_EXIT, although of course more sophisticated
        //ways of handling this message are possible, e.g. by asking the user if he wants to
        //erase the CD-RW.
        private void nClass_OnNonEmptyCDRW(ref NERO_RESPONSE Response)
        {
            Response = NERO_RESPONSE.NERO_RETURN_EXIT;
            Console.WriteLine("nClass_OnNonEmptyCDRW: NERO_RETURN_EXIT");
        }

        //This event will be called when Nero is waiting for a CD to be inserted into the
        //drive.
        private void nClass_OnWaitCD(ref NERO_WAITCD_TYPE WaitCD, ref string WaitCDLocalizedText)
        {
            Console.WriteLine("nClass_OnWaitCD: " + WaitCDLocalizedText);
        }

        //This event will be fired when Nero is waiting for a particular type of media.
        private void nClass_OnWaitCDMediaInfo(ref NERO_MEDIA_TYPE LastDetectedMedia, ref string LastDetectedMediaName, ref NERO_MEDIA_TYPE RequestedMedia, ref string RequestedMediaName)
        {
            Console.WriteLine("nClass_OnWaitCDMediaInfo: Waiting for a particular media type: " + RequestedMediaName);
        }

        //This event will occur when Nero has been waiting for the insertion of a CD for
        //quite a while.
        private void nClass_OnWaitCDReminder()
        {
            Console.WriteLine("nClass_OnWaitCDReminder: Waiting for CD");
        }
        #endregion

        private void nDrive_OnDoneCDInfo(INeroCDInfo pCDInfo)
        {
            Console.WriteLine("nDrive_OnDoneCDInfo: " + pCDInfo.ToString());
        }

        private void nDrive_OnDoneEstimateTrackSize(bool bOk, int BlockSize)
        {
            longOperation = false;
            Console.WriteLine("nDrive_OnDoneEstimateTrackSize: " + bOk + "Blocksize: " + BlockSize);

        }

        private void nDrive_OnDoneImport(ref bool Ok, ref NeroFolder Folder, ref NeroCDStamp CDStamp)
        {
            Console.WriteLine("nDrive_OnDoneImport: " + Ok + Folder.ToString() + CDStamp);
        }

        private void nClass_OnWaitCDDone()
        {
            Console.WriteLine("nClass_OnWaitCDDone");
        }

        private void nClass_OnDriveStatusChanged(int hostID, int targetID, NERO_DRIVECHANGE_RESULT driveStatus)
        {
            Console.WriteLine("nClass_OnDriveStatusChanged: hostID:" + hostID + " targetID:" + targetID + " " + driveStatus);
        }
    }

}
yahoo
Hallo,


menno selber wrappen! Das auch noch ;-)

Vielen Dank,

Yahoo
Gumble
jaha! schaffst Du schon Augenzwinkern
hab den wrapper gleich strong named signiert und in den GAC eingetragen.
Wollte vorhin eigentlich noch den Code etwas erklaeren, aber es musste schnell gehen, weil ich erstmal essen gegangen bin smile
In der OnProgress (Z. 265) ist ein Aufruf der das ProgressForm mit einem neuen Wert updated - genau dieses laesst mein Programm in die Endlosschleife laufen (im Gegensatz wie ich vorhinbehauptet habe, die Instanz alleine reicht aus)
Ausserdem funktion das Progressfensterchen noch nicht wirklich - es wird nur einmal am Anfang gezeichnet und sonst nie (-> weiss, wenn ichs verschieb). Vermutlich ist da auch noch ein Design(denk)fehler. Soll das Fenster in einen eigenen Thread?
Gumble
also wenn ich den ProgressDialog nach dem BurnIsoAudio-aufruf modal aufrufe:
myProgressForm.ShowDialog();
dann funktionierts fast so ich mir es vorgestellt habe. Leider kann ich fuer die Zeit vor dem Brennaufruf keine Statusinformationen liefern, d.h. waehrend der erste While-schleife. Habe es nicht geschaft, da ein Fenster aufzumachen (darf nicht modal sein!) das auch funktioniert. Events wirft NeroCom da leider auch noch nicht...
anbei mal ein Bildchen wies momentan aussieht.
guenni81
@Gumble
Könntest du mir dein Testprojekt mal zukommen lassen???
Die Progressbar ging nämlich beim Tutorial ohne probleme mit.
Gumble
@guenni81
danke fuer die muehen, aber so wie es laeuft reichts mir erstmal. ist ja eh nur ne komponente zum testen. haette halt gern mehr details ueber nerocom@.net gehabt, aber die informationen sind ja sehr spaerlich. ein (vollstaendiges) uml-ablaufdiagramm waer fein - sowas wie 'select recoder', 'add files', 'add dir', 'EstimateTrackSize'. 'burn' usw und das alles in einem zeitlichen zusammenhang bringen...
guenni81
@Gumble
OK, wenn es dir soweit reicht wie du es hast passt es ja ;o)
Aber so ne komplette Libary die die Neroschnittstelle wrappt wäre doch wirklich was sehr feines.
Gumble
Hier nochmal fuer den geneigten NERO user meine bisherige kleine Komponente smile
Anregungen, Verbesserungen und Wuensche gerne aeussern. Vielleicht will ja einer da weiterbasteln - dann koennte man das in die Komponentensammlung aufnehmen.
Was noch geandert werden muss, ist nur noch den 'Trace.Debug' Befehl durch eigene Tracings (oder Console.Write) zu ersetzen.

[Inhalt wrappednero.zip]
CDService_NET.cs
Progress.cs
ColorProgressBar.dll
velgreyer
ich habe leider ein Problem mit der Einbindung der DLL in SharpDevelop. Ich denke dass es mehr daran liegt dass ich nicht genau weiß wie es geht. Ich habe die DLL nach der Anleitung dissambliert, bearbeitet und abschließend in die nerolib.dll zurück"-gewandelt". Ich kann die DLL aber nicht in die using-Klausel einbinden. Ich habe die DLL in das Projekt-Verzeichniss kopiert (was wohl falsch ist).
Wie binde ich die DLL richtig ein?
guenni81
Wie man eine DLL Datei bei SharpDevelop hinzufügt kann ich dir leider nicht beantworten, habe noch nie damit gearbeitet.
S.H.-Teichhof
Zitat:
Wie man eine DLL Datei bei SharpDevelop hinzufügt kann ich dir leider nicht beantworten, habe noch nie damit gearbeitet.

wird ihm ja viel nützen

du must in derProjektmape rechtsklick auf das Projekt und Reverrenz hinzufügen
velgreyer
Ah, jetzt funktioniert das Brennen smile Vielen Dank

vel
guenni81
Mich freut es aber das dieses dennoch kleine Tutorial so beliebt ist und den vielen leute behilflich sein kann
velgreyer
Es ist nunmal um einiges schlanker als die Nero-Docs großes Grinsen

vel