1
// ------------------------------------------------------------------
2 // Copyright (C) 2011-2015 Maruko Toolbox Project
4 // Authors: komaruchan <sandy_0308@hotmail.com>
5 // LunarShaddow <aflyhorse@hotmail.com>
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
16 // express or implied.
17 // See the License for the specific language governing permissions
18 // and limitations under the License.
19 // -------------------------------------------------------------------
23 using System
.Collections
.Generic
;
24 using System
.ComponentModel
;
27 using System
.Runtime
.InteropServices
;
29 using System
.Text
.RegularExpressions
;
30 using System
.Windows
.Forms
;
31 using Microsoft
.WindowsAPICodePack
.Taskbar
;
36 public partial class WorkingForm
: Form
39 /// Initialize a cmd output wrapper.
41 /// <param name="commands">Proposing commands.
42 /// Expecting <see cref="Environment.NewLine"/> as line breaker.</param>
43 /// <param name="workcount">The amount of roposing commands.
44 /// Single-pass work don't need to specify this parameter.</param>
45 public WorkingForm(string commands
, int workcount
= 1)
47 InitializeComponent();
49 WorkQueued
= workcount
;
50 this.Parent
= this.Owner
;
51 StartPosition
= FormStartPosition
.CenterScreen
;
55 /// Gets or sets the proposed commands. Expecting <see cref="Environment.NewLine"/> as line breaker.
56 /// <exception cref="System.ArgumentException">
57 /// An exception is thrown if set it empty or null.</exception>
59 public string Commands
67 if (String
.IsNullOrEmpty(value))
68 throw new ArgumentException("Null or empty commands string.");
75 /// Gets or sets the amount of proposed works.
76 /// <exception cref="System.ArgumentException">
77 /// An exception is thrown if set it zero of negative.</exception>
88 throw new ArgumentException("Negative number? Really?");
95 /// Makesure a file really exists.
97 /// <param name="path">Path to the file.</param>
98 /// <param name="arg">Supplement info.</param>
99 /// <returns>The file exist or not.</returns>
100 public static bool CheckFileExist(string path
, string info
= "")
102 if (!System
.IO
.File
.Exists(path
))
103 MessageBox
.Show("找不到 " + path
+ " 了啦" + Environment
.NewLine
105 return System
.IO
.File
.Exists(path
);
108 #region Private Members Declaration
111 /// Proposed commands.
116 /// Queued works quantity.
118 private int workQueued
;
121 /// Completed works quantity.
123 private int workCompleted
;
126 /// Path to the batch file.
128 private string batPath
;
131 /// Potential working process.
133 private System
.Diagnostics
.Process proc
;
136 /// Frame count of current processing file via FFmpeg.
138 private int frameCount
;
141 /// Path to the tools directory.
143 private string workPath
;
146 /// true if the system is Win7 or later
148 private bool win7supported
;
151 /// true if autoscroll is enabled
153 private bool autoscroll
;
156 /// Internal log, without progress Indicators
158 private StringBuilder internellog
= new StringBuilder();
162 #region Regex Patterns
164 /// Store const regex patterns.
165 /// The Regex objects are made to speed up matchup instead of
166 /// passing the pattern string as arguments from time to time.
168 public static class Patterns
171 /// ffms splitter sample output:
172 /// <para>[8.1%] 273/3357 frames, 56.22 fps, 17.99 kb/s, 25.01 KB, eta 0:00:54, est.size 307.54 KB</para>
174 private const string ffmsRegStr
= @"^\[(?<percent>\d+\.\d+)%\]";
177 /// ffms splitter Regex.
178 /// Available patterns: percent.
180 public static readonly Regex ffmsReg
= new Regex(ffmsRegStr
);
183 /// lavf splitter sample output:
184 /// <para>387 frames: 68.65 fps, 14.86 kb/s, 29.27 KB</para>
186 private const string lavfRegStr
= @"^(?<frame>\d+) frames:";
189 /// lavf splitter Regex.
190 /// Available patterns: frame.
192 public static readonly Regex lavfReg
= new Regex(lavfRegStr
);
195 /// NeroAAC sample output:
196 /// <para>Processed 10 seconds...</para>
198 private const string neroRegStr
= @"Processed (?<duration>\d+) seconds...";
201 /// NeroAAC Progress Regex.
202 /// Available patterns: duration.
204 public static readonly Regex neroReg
= new Regex(neroRegStr
);
207 /// x264 execution sample output:
208 /// <para>X:\toolDIR>"X:\toolDIR\tools\x264_32_tMod-8bit-420.exe" --crf 24 --preset 8 --demuxer ffms
209 /// -r 3 --b 3 --me umh -i 1 --scenecut 60 -f 1:1 --qcomp 0.5 --psy-rd 0.3:0 --aq-mode 2 --aq-strength 0.8
210 /// -o "X:\workDIR\output.ext" "X:\workDIR\input.ext" --vf subtitles --sub "X:\workDIR\sub.ext"
211 /// --acodec faac --abitrate 128</para>
214 /// Without double quote: ^.+>"(?<workDIR>[^"]+)\\x264.+ -o "(?<fileOut>[^"]+)" "(?<fileIn>[^"]+)"
216 private const string fileRegStr
= @">""(?<workDIR>[^""]+)\\x264.+-o ""(?<fileOut>[^""]+)"" ""(?<fileIn>[^""]+)""";
219 /// Filename and working directory Regex.
220 /// Available patterns: workDIR, fileOut, fileIn.
222 public static readonly Regex fileReg
= new Regex(fileRegStr
, RegexOptions
.Singleline
);
225 /// ffmpeg -i sample output:
226 /// <para>Duration: 00:02:20.22, start: 0.000000, bitrate: 827 kb/s</para>
227 /// <para>Stream #0:0: Video: h264 (High), yuv420p, 1280x720, 545 kb/s, 24.42 fps, 23.98 tbr, 1k tbn, 47.95 tbc</para>
228 /// <para>Stream #0:1: Audio: aac, 48000 Hz, stereo, fltp, 128 kb/s</para>
230 private const string ffmpegRegStr
= @"\bDuration: (?<duration>\d{2}:\d{2}:\d{2}\.\d{2}), start: " +
231 @".+: Video: .+ (?<tbr>\d+\.?\d+) tbr, ";
234 /// ffmpeg output Regex.
235 /// Available patterns: duration, tbr.
237 public static readonly Regex ffmpegReg
= new Regex(ffmpegRegStr
, RegexOptions
.Singleline
);
242 #region Native Functions
244 /// Class hosting Native Win32 APIs
246 private class NativeMethods
251 /// Specifies the type of scroll bar.
253 public enum ScrollBarConsts
: int
256 /// Window's standard horizontal scroll bar.
260 /// Window's standard vertical scroll bar.
264 /// Retrieves the position of the scroll box in a scroll bar control.
265 /// The hWnd parameter must be the handle to the scroll bar control.
269 /// Window's standard scroll bar.
275 /// Specifies the commands to scroll bar.
277 public enum ScrollBarCmds
: int
280 /// Scrolls one line down.
284 /// Scrolls left by one unit.
288 /// Scrolls one line up.
292 /// Scrolls right by one unit.
296 /// Scrolls one page up.
300 /// Scrolls left by the width of the window.
304 /// Scrolls one page down.
308 /// Scrolls right by the width of the window.
312 /// The user has dragged the scroll box (thumb) and released the mouse button.
313 /// The HIWORD indicates the position of the scroll box at the end of the drag operation.
315 SB_THUMBPOSITION
= 4,
317 /// The user is dragging the scroll box. This message is sent repeatedly until the user releases the mouse button.
318 /// The HIWORD indicates the position that the scroll box has been dragged to.
322 /// Scrolls to the upper left.
326 /// Scrolls to the upper left.
330 /// Scrolls to the lower right.
334 /// Scrolls to the lower right.
344 /// Indicate the parameters to set or get.
346 public enum ScrollBarFlags
: uint
349 /// The nMin and nMax members contain the minimum and maximum values for the scrolling range.
353 /// The nPage member contains the page size for a proportional scroll bar.
357 /// The nPos member contains the scroll box position, which is not updated while the user drags the scroll box.
361 /// This value is used only when setting a scroll bar's parameters.
362 /// If the scroll bar's new parameters make the scroll bar unnecessary, disable the scroll bar instead of removing it.
364 SIF_DISABLENOSCROLL
= 0x8,
366 /// The nTrackPos member contains the current position of the scroll box while the user is dragging it.
370 /// Combination of SIF_PAGE, SIF_POS, SIF_RANGE, and SIF_TRACKPOS.
372 SIF_ALL
= (SIF_RANGE
| SIF_PAGE
| SIF_POS
| SIF_TRACKPOS
)
376 /// The flash status.
378 public enum FlashWindowFlags
: uint
381 /// Stop flashing. The system restores the window to its original state.
385 /// Flash the window caption.
387 FLASHW_CAPTION
= 0x1,
389 /// Flash the taskbar button.
393 /// Flash both the window caption and taskbar button.
394 /// This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
396 FLASHW_ALL
= (FLASHW_CAPTION
| FLASHW_TRAY
),
398 /// Flash continuously, until the FLASHW_STOP flag is set.
402 /// Flash continuously until the window comes to the foreground.
404 FLASHW_TIMERNOFG
= 0xC
410 public enum Win32Msgs
: uint
413 /// The WM_HSCROLL message is sent to a window when a scroll event occurs in the window's standard horizontal scroll bar.
414 /// This message is also sent to the owner of a horizontal scroll bar control when a scroll event occurs in the control.
418 /// The WM_VSCROLL message is sent to a window when a scroll event occurs in the window's standard vertical scroll bar.
419 /// This message is also sent to the owner of a vertical scroll bar control when a scroll event occurs in the control.
423 /// The WM_CTLCOLORSCROLLBAR message is sent to the parent window of a scroll bar control when the control is about to be drawn.
424 /// By responding to this message, the parent window can use the display context handle to set the background color of the scroll bar control.
426 WM_CTLCOLORSCROLLBAR
= 0x137
430 /// Contains scroll bar parameters to be set by the SetScrollInfo function, or retrieved by the GetScrollInfo function.
431 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/bb787537(v=vs.85).aspx</para>
433 [StructLayout(LayoutKind
.Sequential
)]
434 public struct SCROLLINFO
437 /// Specifies the size, in bytes, of this structure.
441 /// Specifies the scroll bar parameters to set or retrieve.
443 public ScrollBarFlags fMask
;
445 /// Specifies the minimum scrolling position.
449 /// Specifies the maximum scrolling position.
453 /// Specifies the page size, in device units.
454 /// A scroll bar uses this value to determine the appropriate size of the proportional scroll box.
458 /// Specifies the position of the scroll box.
462 /// Specifies the immediate position of a scroll box that the user is dragging.
463 /// An application cannot set the immediate scroll position; the SetScrollInfo function ignores this member.
465 public int nTrackPos
;
469 /// Contains the flash status for a window and the number of times the system should flash the window.
470 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/ms679348(v=vs.85).aspx</para>
472 [StructLayout(LayoutKind
.Sequential
)]
473 public struct FLASHWINFO
476 /// The size of the structure, in bytes.
480 /// A Handle to the Window to be Flashed. The window can be either opened or minimized.
484 /// The Flash Status.
486 public FlashWindowFlags dwFlags
;
488 /// The number of times to Flash the window.
492 /// The rate at which the Window is to be flashed, in milliseconds.
493 /// If Zero, the function uses the default cursor blink rate.
495 public uint dwTimeout
;
499 /// Creates a value for use as a wParam parameter in a message.
500 /// The macro concatenates the specified values.
501 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/ms632664(v=vs.85).aspx</para>
503 /// <param name="wLow">The low-order word of the new value.</param>
504 /// <param name="wHi">The high-order word of the new value.</param>
505 /// <returns>The return value is a WPARAM value.</returns>
506 public static UIntPtr
MakeWParam(uint wLow
, uint wHi
)
508 return (UIntPtr
)MakeLong(wLow
, wHi
);
512 /// Creates a value for use as an lParam parameter in a message.
513 /// The macro concatenates the specified values.
514 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/ms632661(v=vs.85).aspx</para>
516 /// <param name="wLow">The low-order word of the new value.</param>
517 /// <param name="wHi">The high-order word of the new value. </param>
518 /// <returns>The return value is an LPARAM value. </returns>
519 public static IntPtr
MakeLParam(uint wLow
, uint wHi
)
521 return (IntPtr
)MakeLong(wLow
, wHi
);
529 /// Retrieves the high-order word from the specified 32-bit value.
530 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/ms632657(v=vs.85).aspx</para>
532 /// <param name="ptr">The value to be converted.</param>
533 /// <returns>The return value is the high-order word of the specified value.</returns>
534 public static uint HiWord(IntPtr ptr
)
536 return ((uint)ptr
>> 16) & 0xFFFFu
;
540 /// Retrieves the low-order word from the specified value.
541 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/ms632659(v=vs.85).aspx</para>
543 /// <param name="ptr">The value to be converted.</param>
544 /// <returns>The return value is the low-order word of the specified value.</returns>
545 public static uint LoWord(IntPtr ptr
)
547 return (uint)ptr
& 0xFFFFu
;
551 /// Creates a LONG value by concatenating the specified values.
552 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/ms632660(v=vs.85).aspx</para>
554 /// <param name="wLow">The low-order word of the new value.</param>
555 /// <param name="wHi">The high-order word of the new value.</param>
556 /// <returns>The return value is a LONG value.</returns>
557 public static uint MakeLong(uint wLow
, uint wHi
)
559 return (wLow
& 0xFFFFu
) | ((wHi
& 0xFFFFu
) << 16);
565 /// The GetScrollInfo function retrieves the parameters of a scroll bar,
566 /// including the minimum and maximum scrolling positions, the page size,
567 /// and the position of the scroll box (thumb).
568 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/bb787583(v=vs.85).aspx</para>
570 /// <param name="hWnd">Handle to a scroll bar control or a window with a standard scroll bar,
571 /// depending on the value of the fnBar parameter. </param>
572 /// <param name="fnBar">Specifies the type of scroll bar for which to retrieve parameters.</param>
573 /// <param name="lpsi">Pointer to a SCROLLINFO structure. Before calling GetScrollInfo, set the cbSize member to sizeof(SCROLLINFO),
574 /// and set the fMask member to specify the scroll bar parameters to retrieve.
575 /// Before returning, the function copies the specified parameters to the appropriate members of the structure.</param>
576 /// <returns>If the function retrieved any values, the return value is nonzero.</returns>
577 [DllImport("user32.dll")]
578 [return: MarshalAs(UnmanagedType
.Bool
)]
579 public static extern bool GetScrollInfo(
581 ScrollBarConsts fnBar
,
582 ref SCROLLINFO lpsi
);
585 /// The SetScrollInfo function sets the parameters of a scroll bar, including the minimum and maximum scrolling positions,
586 /// the page size, and the position of the scroll box (thumb). The function also redraws the scroll bar, if requested.
587 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/bb787595(v=vs.85).aspx</para>
589 /// <param name="hWnd">Handle to a scroll bar control or a window with a standard scroll bar,
590 /// depending on the value of the fnBar parameter. </param>
591 /// <param name="fnBar">Specifies the type of scroll bar for which to set parameters.</param>
592 /// <param name="lpsi">Pointer to a SCROLLINFO structure. Before calling SetScrollInfo, set the cbSize member of the structure to sizeof(SCROLLINFO),
593 /// set the fMask member to indicate the parameters to set, and specify the new parameter values in the appropriate members.</param>
594 /// <param name="fRedraw">Specifies whether the scroll bar is redrawn to reflect the changes to the scroll bar.
595 /// If this parameter is TRUE, the scroll bar is redrawn, otherwise, it is not redrawn. </param>
596 /// <returns>The current position of the scroll box.</returns>
597 [DllImport("user32.dll")]
598 public static extern int SetScrollInfo(
600 ScrollBarConsts fnBar
,
602 [MarshalAs(UnmanagedType
.Bool
)] bool fRedraw
);
605 /// Flashes the specified window. It does not change the active state of the window.
606 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/ms679347(v=vs.85).aspx</para>
608 /// <param name="pwfi">A pointer to a FLASHWINFO structure.</param>
609 /// <returns>The return value specifies the window's state before the call to the FlashWindowEx function.
610 /// If the window caption was drawn as active before the call, the return value is nonzero. Otherwise, the return value is zero.</returns>
611 [DllImport("user32.dll")]
612 public static extern bool FlashWindowEx(ref FLASHWINFO pwfi
);
615 /// Places (posts) a message in the message queue associated with the thread that created
616 /// the specified window and returns without waiting for the thread to process the message.
617 /// <para>http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944(v=vs.85).aspx</para>
619 /// <param name="hWnd">A handle to the window whose window procedure is to receive the message.</param>
620 /// <param name="Msg">The message to be posted.</param>
621 /// <param name="wParam">Additional message-specific information.</param>
622 /// <param name="lParam">Additional message-specific information.</param>
623 /// <returns>If the function succeeds, the return value is nonzero.</returns>
624 [DllImport("user32.dll")]
625 [return: MarshalAs(UnmanagedType
.Bool
)]
626 public static extern bool PostMessage(
629 [MarshalAs(UnmanagedType
.SysUInt
)] UIntPtr wParam
,
630 [MarshalAs(UnmanagedType
.SysInt
)] IntPtr lParam
);
636 private void WorkingForm_Load(object sender
, EventArgs e
)
638 // save commands into a batch file
639 batPath
= System
.IO
.Path
.Combine(
640 Environment
.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget
.User
),
641 "xiaowan" + DateTime
.Now
.ToFileTimeUtc().ToString() + ".bat");
642 var encoder
= Encoding
.GetEncoding(0);
643 var sw
= new System
.IO
.StreamWriter(batPath
, false, encoder
);
644 sw
.WriteLine(Commands
);
648 richTextBoxOutput
.Select();
649 // check win7 supported
650 win7supported
= (Environment
.OSVersion
.Version
.Major
> 6 ||
651 (Environment
.OSVersion
.Version
.Major
== 6 && Environment
.OSVersion
.Version
.Minor
>= 1));
653 TaskbarManager
.Instance
.SetProgressState(TaskbarProgressBarState
.Normal
);
654 // validate the command string
655 if (Commands
.Equals(encoder
.GetString(encoder
.GetBytes(Commands
))))
659 MessageBox
.Show("Path or filename contains invalid characters, please rename and retry."
660 + Environment
.NewLine
+
661 "路径或文件名含有不可识别的字符,请重命名后重试。");
664 notifyIcon
.Visible
= true;
665 MainForm main
= (MainForm
)this.Owner
;
666 workPath
= main
.workPath
;
670 private void WorkingForm_FormClosing(object sender
, FormClosingEventArgs e
)
672 // check remaining works
673 if (!(proc
== null || proc
.HasExited
))
675 // ask if user hit close button on any accident
676 var result
= MessageBox
.Show("Processing is still undergoing, confirm exit?",
677 "Xiaowan", MessageBoxButtons
.YesNo
, MessageBoxIcon
.Warning
);
678 if (result
== System
.Windows
.Forms
.DialogResult
.No
)
680 // cancel event and return
687 // clean up temp batch file
688 System
.IO
.File
.Delete(batPath
);
691 private void buttonAbort_Click(object sender
, EventArgs e
)
696 private void buttonSave_Click(object sender
, EventArgs e
)
698 // prohibit saving before work completion
700 MessageBox
.Show("Saving before completion is not recommended." +
701 Environment
.NewLine
+ "Please manually abort the process or wait patiently.");
704 var savDlg
= new SaveFileDialog();
705 savDlg
.FileName
= "log_" + DateTime
.Now
.ToShortDateString().Replace('/', '-');
706 savDlg
.Filter
= "Log files|*.log|All files|*.*";
707 savDlg
.FilterIndex
= 1;
708 savDlg
.RestoreDirectory
= true;
709 if (savDlg
.ShowDialog() == System
.Windows
.Forms
.DialogResult
.OK
)
710 System
.IO
.File
.WriteAllText(savDlg
.FileName
, internellog
.ToString());
714 private void richTextBoxOutput_VScroll(object sender
, EventArgs e
)
716 var info
= new NativeMethods
.SCROLLINFO();
717 info
.cbSize
= Convert
.ToUInt32(Marshal
.SizeOf(info
));
718 info
.fMask
= NativeMethods
.ScrollBarFlags
.SIF_ALL
;
719 NativeMethods
.GetScrollInfo(richTextBoxOutput
.Handle
, NativeMethods
.ScrollBarConsts
.SB_VERT
, ref info
);
720 autoscroll
= (info
.nTrackPos
+ richTextBoxOutput
.Font
.Height
721 > info
.nMax
- richTextBoxOutput
.ClientSize
.Height
);
724 private void WorkingForm_Resize(object sender
, EventArgs e
)
726 if (this.WindowState
== FormWindowState
.Minimized
)
727 BalloonTip("丸子跑到这里了喔~", 75);
730 private void notifyIcon_MouseClick(object sender
, MouseEventArgs e
)
733 this.WindowState
= FormWindowState
.Normal
;
737 private void richTextBoxOutput_Enter(object sender
, EventArgs e
)
739 this.ActiveControl
= null;
745 /// Start the working process.
747 private void ProcStart()
750 CheckFileExist(batPath
);
751 var processInfo
= new System
.Diagnostics
.ProcessStartInfo(batPath
, "2>&1");
752 processInfo
.WorkingDirectory
= System
.IO
.Directory
.GetCurrentDirectory();
753 processInfo
.CreateNoWindow
= true;
754 processInfo
.UseShellExecute
= false;
755 processInfo
.RedirectStandardOutput
= true;
756 proc
= System
.Diagnostics
.Process
.Start(processInfo
);
757 // attach exit event handler
758 proc
.EnableRaisingEvents
= true;
759 proc
.Exited
+= new EventHandler(ProcExit
);
760 // setup asynchronous reading
761 proc
.OutputDataReceived
+= new System
.Diagnostics
.DataReceivedEventHandler(OutputHandler
);
762 proc
.BeginOutputReadLine();
766 /// Process Exit event handler. Automatically called when process exit normally.
768 private void ProcExit(object sender
, EventArgs e
)
772 buttonAbort
.InvokeIfRequired(() =>
773 buttonAbort
.Enabled
= false);
776 TaskbarManager
.Instance
.SetProgressState(TaskbarProgressBarState
.NoProgress
);
777 // wait a little bit for the last asynchronous reading
778 System
.Threading
.Thread
.Sleep(75);
780 Print(Environment
.NewLine
+ "Work Complete!");
781 // fire a warning if something went wrong
782 // this feature need %ERRORLEVEL% support in batch commands
783 if (proc
.ExitCode
!= 0)
785 Print(Environment
.NewLine
+
786 "Potential Error detected. Please double check the log.");
787 Print(Environment
.NewLine
+
788 "Exit code is: " + proc
.ExitCode
.ToString());
790 // flash form and show balloon tips
792 BalloonTip(@"完成了喵~ (= ω =)");
794 // shutdown the system if required
795 MainForm main
= (MainForm
)this.Owner
;
796 if (main
.shutdownState
)
798 System
.Diagnostics
.Process
.Start("shutdown", "-s");
799 // wait a bit to ensure synchronization
800 System
.Threading
.Thread
.Sleep(75);
801 if (System
.Windows
.Forms
.DialogResult
.Cancel
== MessageBox
.Show(
802 "System will shutdown in 20 seconds. Click \"Cancel\" to stop countdown."
803 + Environment
.NewLine
+
804 "系统将在20秒后自动关机。点击“取消”停止倒计时。",
805 "Warning", MessageBoxButtons
.OKCancel
))
807 System
.Diagnostics
.Process
.Start("shutdown", "-a");
813 /// Manually call this method to abort all workings.
815 private void ProcAbort()
817 // return value is useless when force aborted
818 proc
.CancelOutputRead();
819 // exit process should be omitted too
820 proc
.Exited
-= new EventHandler(ProcExit
);
822 killProcTree(proc
.Id
);
823 // reset taskbar progress
825 TaskbarManager
.Instance
.SetProgressState(TaskbarProgressBarState
.NoProgress
);
826 // Print abort message to log
827 Print(Environment
.NewLine
+ "Work is aborted by user.");
831 /// Asynchronous reading DataReceived event handler.
833 private void OutputHandler(object sender
, System
.Diagnostics
.DataReceivedEventArgs e
)
835 if (!String
.IsNullOrEmpty(e
.Data
))
837 // convert and log first
838 Print(e
.Data
+ Environment
.NewLine
);
839 // test if it is command
840 Match result
= Patterns
.fileReg
.Match(e
.Data
);
844 progressBarX264
.InvokeIfRequired(() =>
845 progressBarX264
.Style
= ProgressBarStyle
.Blocks
848 frameCount
= EstimateFrame(workPath
, result
.Groups
["fileIn"].Value
);
851 result
= Patterns
.ffmsReg
.Match(e
.Data
);
853 UpdateProgress(Double
.Parse(result
.Groups
["percent"].Value
) / 100);
857 result
= Patterns
.lavfReg
.Match(e
.Data
);
859 UpdateProgress(Double
.Parse(result
.Groups
["frame"].Value
) / frameCount
);
863 result
= Patterns
.neroReg
.Match(e
.Data
);
865 internellog
.AppendLine(e
.Data
);
872 /// Kill a process as well as all childs by PID.
874 /// <param name="pid">The PID of the target process.</param>
875 private void killProcTree(int pid
)
878 foreach (var m
in new System
.Management
.ManagementObjectSearcher(
879 "Select * From Win32_Process Where ParentProcessID=" + pid
).Get())
881 killProcTree(Convert
.ToInt32(m
["ProcessID"]));
883 // then suicide, usually threads throw exceptions when killed. Dump them silently.
886 System
.Diagnostics
.Process
.GetProcessById(pid
).Kill();
888 catch (ArgumentException
) { }
892 /// Update Work Count UI on call. Each call will bump up completed work count by 1.
894 private void UpdateWorkCountUI()
897 this.InvokeIfRequired(() =>
898 this.Text
= "Xiaowan (" + workCompleted
+ '/' + WorkQueued
+ ')');
899 this.labelworkCount
.InvokeIfRequired(() =>
900 labelworkCount
.Text
= workCompleted
.ToString() + '/' + WorkQueued
+ " Completed");
904 /// Update Progress Bar as well as the number on it.
906 /// <param name="value">Progress expressed in decimal (0.00-1.00).</param>
907 private void UpdateProgress(double value)
909 // Some kind of safeguard
915 progressBarX264
.InvokeIfRequired(() =>
916 progressBarX264
.Value
= Convert
.ToInt32(value * progressBarX264
.Maximum
));
917 labelProgress
.InvokeIfRequired(() =>
918 labelProgress
.Text
= value.ToString("P"));
920 TaskbarManager
.Instance
.SetProgressValue(
921 Convert
.ToInt32(value * progressBarX264
.Maximum
), progressBarX264
.Maximum
);
922 notifyIcon
.Text
= "小丸工具箱" + Environment
.NewLine
+
923 labelworkCount
.Text
+ " - " + labelProgress
.Text
;
927 /// Get a rough estimation on frame counts via FFmpeg.
928 /// If failed, return <see cref="Int32.MaxValue"/> instead.
930 /// <param name="workPath">Path to ffmpeg binary.</param>
931 /// <param name="filePath">Path to target file.</param>
932 /// <returns>Estimated frame count. 1% tolerance added.</returns>
933 private int EstimateFrame(string workPath
, string filePath
)
935 string ffmpegPath
= System
.IO
.Path
.Combine(workPath
, "ffmpeg.exe");
936 CheckFileExist(ffmpegPath
);
937 var processInfo
= new System
.Diagnostics
.ProcessStartInfo(ffmpegPath
, "-i \"" + filePath
+ '"');
938 processInfo
.CreateNoWindow
= true;
939 processInfo
.UseShellExecute
= false;
940 processInfo
.RedirectStandardError
= true;
941 var ffproc
= System
.Diagnostics
.Process
.Start(processInfo
);
943 string mediaInfo
= ffproc
.StandardError
.ReadToEnd();
944 Print("Input file: " + filePath
+ Environment
.NewLine
);
945 Print(mediaInfo
+ Environment
.NewLine
);
946 ffproc
.WaitForExit();
947 var result
= Patterns
.ffmpegReg
.Match(mediaInfo
);
950 Print("Warning: Error detected on previous file. Estimatation may not work."
951 + Environment
.NewLine
);
952 return Int32
.MaxValue
;
955 // add a 1% tolerance to avoid unintentional overflow on progress bar
956 return Convert
.ToInt32(TimeSpan
.Parse(result
.Groups
["duration"].Value
).TotalSeconds
957 * Double
.Parse(result
.Groups
["tbr"].Value
) * 1.01);
961 /// Flash the current form.
963 /// <returns>Whether the form need flash or not.</returns>
964 private bool FlashForm()
966 var info
= new NativeMethods
.FLASHWINFO();
967 info
.cbSize
= Convert
.ToUInt32(Marshal
.SizeOf(info
));
968 this.InvokeIfRequired(() =>
969 info
.hwnd
= this.Handle
);
970 info
.dwFlags
= NativeMethods
.FlashWindowFlags
.FLASHW_ALL
|
971 NativeMethods
.FlashWindowFlags
.FLASHW_TIMERNOFG
;
975 return NativeMethods
.FlashWindowEx(ref info
);
979 /// Pop a balloon tip.
981 /// <param name="notes">The content to show.</param>
982 /// <param name="timeout">Tip timeout.</param>
983 private void BalloonTip(string notes
, int timeout
= 500)
985 MainForm main
= (MainForm
)this.Owner
;
988 notifyIcon
.Visible
= true;
989 notifyIcon
.ShowBalloonTip(timeout
, "小丸工具箱", notes
, ToolTipIcon
.Info
);
994 /// Append and scroll Textbox if needed.
996 /// <param name="str">String to append.</param>
997 private void Print(string str
)
999 richTextBoxOutput
.InvokeIfRequired(() =>
1001 richTextBoxOutput
.AppendText(str
);
1004 var info
= new NativeMethods
.SCROLLINFO();
1005 info
.cbSize
= Convert
.ToUInt32(Marshal
.SizeOf(info
));
1006 info
.fMask
= NativeMethods
.ScrollBarFlags
.SIF_RANGE
;
1007 NativeMethods
.GetScrollInfo(richTextBoxOutput
.Handle
, NativeMethods
.ScrollBarConsts
.SB_VERT
, ref info
);
1008 NativeMethods
.PostMessage(richTextBoxOutput
.Handle
, NativeMethods
.Win32Msgs
.WM_VSCROLL
,
1009 NativeMethods
.MakeWParam((uint)NativeMethods
.ScrollBarCmds
.SB_THUMBPOSITION
, (uint)info
.nMax
), IntPtr
.Zero
);