/// <summary> /// Executes a new gPhoto2 process and retrieves its output. /// </summary> /// <param name="commandLineParameters">The command line paramters, which are passed to the process.</param> /// <returns>Returns what the process wrote to the standard output.</returns> public Task <string> ExecuteAsync(string commandLineParameters) { // Creates a gPhoto2 command, which is scheduled to run on the camera, it contains a task completion source, which resolves when the // command has been executed GPhoto2Command gPhoto2Command = new GPhoto2Command { Command = () => Task <string> .Run(() => { // Creates the start information that are needed to run the process ProcessStartInfo processStartInfo = new ProcessStartInfo { Arguments = string.IsNullOrWhiteSpace(this.StandardCommandLineParameters) ? commandLineParameters : string.Concat(this.StandardCommandLineParameters, " ", commandLineParameters), FileName = "gphoto2", UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, StandardOutputEncoding = Encoding.UTF8, }; // Sets the language in which the application is to be started (the languages is set to american english in order to make it // easier to parse the output regardless of the system language) if (processStartInfo.EnvironmentVariables.ContainsKey("LANG")) { processStartInfo.EnvironmentVariables["LANG"] = "en_US.UTF-8"; } else { processStartInfo.EnvironmentVariables.Add("LANG", "en_US.UTF-8"); } // Starts the process Process process = new Process(); process.StartInfo = processStartInfo; process.Start(); // Reads the output that the process wrote to the standard output string output = process.StandardOutput.ReadToEnd(); // Waits till the process has finished process.WaitForExit(); // Checks if the output of gPhoto2 contains any errors, if so a camera exception is thrown CameraException.DetectCameraErrors(output); // Returns the output of the process, so that the user is able to parse it return(output); }) }; // Schedules the camera command, so that it can run on the camera (it must be scheduled to ensure that only one command is executed at // a time) this.cameraActionBlock.Post(gPhoto2Command); // Awaits the execution of the scheduled camera command return(gPhoto2Command.TaskCompletionSource.Task); }
/// <summary> /// Executes the specified command line parameters in the gPhoto2 interactive shell process. This method of executing a command has better /// performace, because the shell mode process has only to be spawned once and can then be reused. /// </summary> /// <param name="commandLineParameters">The command line paramters, which are passed to the process.</param> public Task <string> ExecuteInteractiveAsync(string commandLineParameters) { // Creates a gPhoto2 command, which is scheduled to run on the camera, it contains a task completion source, which resolves when the // command has been executed GPhoto2Command gPhoto2Command = new GPhoto2Command { Command = () => Task <string> .Run(() => { // Checks whether the gPhoto2 interactive shell process has been started, yet, if not then a new one is spawned if (this.gPhoto2InteractiveShellProcess == null) { // Creates the start information that are needed to run the gPhoto2 process in the interactive shell mode ProcessStartInfo processStartInfo = new ProcessStartInfo { Arguments = string.Concat("--shell ", this.StandardCommandLineParameters), FileName = "gphoto2", UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, StandardOutputEncoding = Encoding.UTF8, }; // Sets the language in which the application is to be started (the languages is set to american english in order to make // it easier to parse the output regardless of the system language) if (processStartInfo.EnvironmentVariables.ContainsKey("LANG")) { processStartInfo.EnvironmentVariables["LANG"] = "en_US.UTF-8"; } else { processStartInfo.EnvironmentVariables.Add("LANG", "en_US.UTF-8"); } // Starts the process gPhoto2 process in the interactive shell mode this.gPhoto2InteractiveShellProcess = new Process(); this.gPhoto2InteractiveShellProcess.StartInfo = processStartInfo; this.gPhoto2InteractiveShellProcess.Start(); } // Executes the specified command by writing it to the standard input of the gPhoto2 interactive shell process this.gPhoto2InteractiveShellProcess.StandardInput.WriteLine(commandLineParameters); // Reads the output of the process line by line and returns it, the end of the output is detected by checking if the read // output line starts with "gphoto2:" (in the interactive shell mode of gPhoto2 prints out the prompt "gphoto2:" followed // by the current path) int outputCharacterCode; int currentLineNumber = 1; string currentOutputLine = string.Empty; List <string> outputLines = new List <string>(); while ((outputCharacterCode = this.gPhoto2InteractiveShellProcess.StandardOutput.Read()) != -1) { // Converts the current character code to a character char outputCharacter = Convert.ToChar(outputCharacterCode); // Checks what kind of character was read if (outputCharacter == '\r') { // When a carriage return is read, then nothing is done (since the look-ahead is only one character and some systems // need two characters for a new line, it is much safer to only watch for line feed and ignore the carriage return // alltogether) continue; } else if (outputCharacter == '\n') { // When the read character is a line feed, then the current line is added to the result (but empty lines and the // first two lines, which just contain the shell prompt and a repitition of the command that is to be executed, are // not added, because their are not needed) if (currentLineNumber > 2 && !string.IsNullOrWhiteSpace(currentOutputLine)) { outputLines.Add(currentOutputLine); } // After the current line has been added to the result or discarded, the current line is reset to empty currentOutputLine = string.Empty; // Counts up the current line number, because the algorithm has to know in what line it currently is currentLineNumber += 1; } else { // All other characters are added to the content of the current line currentOutputLine += outputCharacter; } // Finally it is checked whether the output has reached its end (which is when the line contains the shell prompt // "ghoto2:" and when it is not the first line, because the first line contains a shell prompt as well), if so then the // reading of the output of gPhoto2 is finished if (currentOutputLine.ToUpperInvariant().StartsWith("GPHOTO2:") && currentLineNumber > 1) { break; } } // Joins all the lines written to the output together, so that they can be returned as a single string string output = string.Join(Environment.NewLine, outputLines); // Checks if the output of gPhoto2 contains any errors, if so a camera exception is thrown CameraException.DetectCameraErrors(output); // Returns the output of the process, so that the user is able to parse it return(output); }) }; // Schedules the camera command, so that it can run on the camera (it must be scheduled to ensure that only one command is executed at // a time) this.cameraActionBlock.Post(gPhoto2Command); // Awaits the execution of the scheduled camera command return(gPhoto2Command.TaskCompletionSource.Task); }