[英]Can I prevent the IOException from opening the messagebox?
//注1:有些本地化的消息是直接翻譯的,所以在你的電腦上可能會有所不同,但意思是一樣的。
//注2:本程序是在.NET Framework 4.5, Release, x64 下構建的。
我正在設計一個可以靜默自動備份閃存驅動器的程序。
在復制方法中,我使用如下代碼:
//Note: the Cout(string) method is a logging method, acturally equivalent to Console.WriteLine(string)
public void CopyMoveDisk(string fromdir, string todir, int times = 0)
{
try
{
if (PauseToken)
{
Cout("Copy: paused");
STTimer t = new STTimer(o => { CopyMoveDisk(fromdir, todir, times); }, null, 5000, -1);
Thread.Sleep(6000);
t.Dispose();
return;
}
else
{
try
{
if (!Directory.Exists(todir))
Directory.CreateDirectory(todir);
var filessmall = from f in Directory.GetFiles(fromdir)
where new FileInfo(f).Length <= 100 * Math.Pow(2, 20)
orderby new FileInfo(f).Length
select f;
var filesbig = from f in Directory.GetFiles(fromdir)
where new FileInfo(f).Length > 100 * Math.Pow(2, 20)
orderby new FileInfo(f).Length
select f;
Cout("Copy: small file region");
// Copy the small files (<= 100MiB)
foreach (string file in filessmall)
{
s.CopyingFile = todir + Path.GetFileName(file);
if (File.Exists(todir + Path.GetFileName(file)))
{
if (new FileInfo(file).Length != new FileInfo(todir + Path.GetFileName(file)).Length)
{
Cout($"Copy true: {file} => {todir + Path.GetFileName(file)}: Length = {new FileInfo(todir + Path.GetFileName(file)).Length}");
File.Copy(file, todir + Path.GetFileName(file), true);
}
else
{
Cout($"Exist: {file} => {todir + Path.GetFileName(file)}: Length = {new FileInfo(todir + Path.GetFileName(file)).Length}");
}
}
else
{
Cout($"Copy: {file} => {todir + Path.GetFileName(file)}");
File.Copy(file, todir + Path.GetFileName(file), true);
}
s.CopyingFile = string.Empty;
}
Cout("Copy: small file region end");
Cout($"Copy: directory region: {times} time(s)");
// Copy the sub directories
foreach (string sub in Directory.GetDirectories(fromdir))
{
if (!sub.Contains("System Volume Information"))
{
Cout($"Copy: {sub + "\\"} => {todir + Path.GetFileName(sub) + "\\"}");
CopyMoveDisk(sub + "\\", todir + Path.GetFileName(sub) + "\\", times + 1);
}
}
Cout($"Copy: directory region end: {times} time(s)");
Cout("Copy: big file region");
// Copy the big files (> 100MiB)
foreach (string file in filesbig)
{
s.CopyingFile = todir + Path.GetFileName(file);
if (File.Exists(todir + Path.GetFileName(file)))
{
if (new FileInfo(file).Length != new FileInfo(todir + Path.GetFileName(file)).Length)
{
Cout($"Copy true: {file} => {todir + Path.GetFileName(file)}: Length = {new FileInfo(todir + Path.GetFileName(file)).Length}");
File.Copy(file, todir + Path.GetFileName(file), true);
}
else
{
Cout($"Exist: {file} => {todir + Path.GetFileName(file)}: Length = {new FileInfo(todir + Path.GetFileName(file)).Length}");
}
}
else
{
Cout($"Copy: {file} => {todir + Path.GetFileName(file)}");
File.Copy(file, todir + Path.GetFileName(file), true);
}
s.CopyingFile = string.Empty;
}
Cout("Copy: big file region end");
}
catch (Exception ex)
{
Cout($"Copy: -----Exception {ex} {Environment.NewLine}----------");
}
}
}
catch (Exception ex)
{
Cout($"Copy: -----Exception {ex} {Environment.NewLine}{s}{Environment.NewLine}----------");
}
}
查看代碼后,我們來設想一種情況:
用戶插入 SD 卡讀卡器。 復制文件時,SD 卡不知何故斷開連接,但讀卡器仍然插入(可能是因為接觸不良)。
每當您在沒有卡的情況下插入讀卡器時,Windows 資源管理器都會警告您“請將磁盤插入‘SD 卡 (E:\\)’”。
但是當這種情況發生在這個程序上時,該方法並沒有立即拋出異常。 相反,它顯示了一個消息框,如:
|---USBBackup.exe - 沒有磁盤|
| 驅動器中沒有磁盤。 請將磁盤插入驅動器 E: |
|取消| |重試| |繼續|
如果我單擊取消按鈕(或繼續按鈕?),則會拋出異常:
System.IO.IOException: 驅動器中的軟盤不正確。
將 %2(卷序列號:%3)插入驅動器 %1。
在 System.IO.__Error.WinIOError(Int32 errorCode, String mightFullPath)
在 System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite, Boolean checkHost)
在 USBBackup.Form1.CopyMoveDisk(String fromdir, String todir, Int32 times)
//注3:不知何故,消息框不會顯示在我的 Windows 10 虛擬機上。
//相反,它會直接拋出異常:
System.IO.IOException: 設備未准備好。
在 System.IO.__Error.WinIOError(Int32 errorCode, String mightFullPath)
在 System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite, Boolean checkHost)
在 USBBackup.Form1.CopyMoveDisk(String fromdir, String todir, Int32 times)
//但它顯示在我的 Windows 7 VM 上。
//或者可能是因為我在Win10 VM上安裝了.Net Framework 4.8,但在Win7 VM上安裝了4.5。
既然我不想讓這個程序打擾用戶,我該怎么做才能避免顯示消息框?
您將需要使用SEM_FAILCRITICALERRORS
調用SetErrorMode API 以禁用系統消息框,然后SEM_FAILCRITICALERRORS
其設置回來。
創建一個內部類NativeMethods
:
internal static class NativeMethods
{
[DllImport("kernel32.dll")]
internal static extern ErrorModes SetErrorMode(ErrorModes uMode);
[Flags]
internal enum ErrorModes : uint
{
SYSTEM_DEFAULT = 0x0,
SEM_FAILCRITICALERRORS = 0x0001,
SEM_NOALIGNMENTFAULTEXCEPT = 0x0004,
SEM_NOGPFAULTERRORBOX = 0x0002,
SEM_NOOPENFILEERRORBOX = 0x8000
}
}
示例用法:
void BackupFiles()
{
var prevMode = NativeMethods.SetErrorMode(NativeMethods.SEM_FAILCRITICALERRORS);
try
{
// attempt to copy the files
// from the removable device
}
finally
{
NativeMethods.SetErrorMode(prevMode);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.