c#wpf SaveFileDialog即使在内部也会崩溃Try..Catch
我有一个WPF应用程序,其中我使用了一个SaveFileDialog。 流程如下: 1-用户使用SaveFileDialog选择文件名并关闭对话框 2-应用程序尝试写入文件 3-尝试写入文件时,如果文件被锁定,将引发IOException 4-如果我再次尝试打开SaveFileDialog,应用程序将崩溃,并在ntdll.dll上显示“堆已损坏” 我想不出一个解决办法。即使在一次尝试中,也会发现应用程序崩溃 SaveFileDialog的代码c#wpf SaveFileDialog即使在内部也会崩溃Try..Catch,c#,wpf,C#,Wpf,我有一个WPF应用程序,其中我使用了一个SaveFileDialog。 流程如下: 1-用户使用SaveFileDialog选择文件名并关闭对话框 2-应用程序尝试写入文件 3-尝试写入文件时,如果文件被锁定,将引发IOException 4-如果我再次尝试打开SaveFileDialog,应用程序将崩溃,并在ntdll.dll上显示“堆已损坏” 我想不出一个解决办法。即使在一次尝试中,也会发现应用程序崩溃 SaveFileDialog的代码 try{ Dispatcher.BeginI
try{
Dispatcher.BeginInvoke(new Action(() =>
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Reset();
sfd.AddExtension = true;
sfd.CheckFileExists = false;
sfd.CheckPathExists = true;
sfd.CreatePrompt = false;
sfd.OverwritePrompt = true;
sfd.DefaultExt = defaultExt;
sfd.Filter = filter;
sfd.Title = "Save As " + fileTypeDisplay;
sfd.InitialDirectory = specialFolder;
sfd.FileName = newFileNameNoExt;
sfd.FilterIndex = 1;
if (!string.IsNullOrEmpty(specialFolder))
{
FileDialogCustomPlace cp = new FileDialogCustomPlace(specialFolder); // does not throw exceptions
sfd.CustomPlaces.Add(cp);
}
try
{
if (sfd.ShowDialog(MyMainWindow) == true) //<-- ERROR HERE
{
fileToSave = sfd.FileName;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
sfd = null;
}
})).Wait();
}
catch(exception ex)
{
...log exception...
}
试试看{
Dispatcher.BeginInvoke(新操作(()=>
{
SaveFileDialog sfd=新建SaveFileDialog();
sfd.Reset();
sfd.AddExtension=真;
sfd.CheckFileExists=false;
sfd.CheckPathExists=true;
sfd.CreatePrompt=false;
sfd.OverwritePrompt=true;
sfd.DefaultExt=DefaultExt;
sfd.过滤器=过滤器;
sfd.Title=“另存为”+文件类型显示;
sfd.InitialDirectory=specialFolder;
sfd.FileName=新文件名noext;
sfd.FilterIndex=1;
如果(!string.IsNullOrEmpty(specialFolder))
{
FileDialogCustomPlace cp=新建FileDialogCustomPlace(specialFolder);//不引发异常
sfd.CustomPlaces.Add(cp);
}
尝试
{
如果(sfd.ShowDialog(MyMainWindow)==true)/这不是答案,而是我如何解决崩溃的。这是很久以前的遗留代码,线索是崩溃总是在异常之后发生。但是为什么异常会导致SaveFileDialog出现问题并导致应用程序崩溃
深入了解我学到的代码,下面的代码是在用户在SaveFileDialog上选择文件后执行的
注意对catch块中的方法另一个用户islockingpkg的调用
当我注释掉对该方法的调用时,对该问题的SaveFileDialog.ShowDialog()的调用停止,以使应用程序崩溃。我将尝试按照其他建议查看其行为
如果有人知道为什么会发生这种情况,欢迎发表评论
FileStream strm = null;
try
{
strm = fi.Open(FileMode.Open, forFileAccessMode, fileShare);
}
catch (IOException) // the file is already open
{
...
fiuEx.IsByOtherUser = AnotherUserIsLockingPkg(filePath);
...
}
catch (Exception ex)
{
...
}
finally
{
....
}
下面的代码用于检查文件是否被其他应用程序锁定。它使用了一些API调用。看起来此代码是从
下面列出了AnotherUserIsLockingPkg的方法
#region Check if another user's process is locking a pkg
[StructLayout(LayoutKind.Sequential)]
private struct RM_UNIQUE_PROCESS
{
public int dwProcessId;
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
}
private const int RmRebootReasonNone = 0;
private const int CCH_RM_MAX_APP_NAME = 255;
private const int CCH_RM_MAX_SVC_NAME = 63;
//private enum RM_APP_TYPE
//{
// RmUnknownApp = 0,
// RmMainWindow = 1,
// RmOtherWindow = 2,
// RmService = 3,
// RmExplorer = 4,
// RmConsole = 5,
// RmCritical = 1000
//}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct RM_PROCESS_INFO
{
public RM_UNIQUE_PROCESS Process;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
public string strAppName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
public string strServiceShortName;
//public RM_APP_TYPE ApplicationType;
public uint AppStatus;
public uint TSSessionId;
[MarshalAs(UnmanagedType.Bool)]
public bool bRestartable;
}
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
private static extern int RmRegisterResources(uint pSessionHandle,
UInt32 nFiles,
string[] rgsFilenames,
UInt32 nApplications,
[In] RM_UNIQUE_PROCESS[] rgApplications,
UInt32 nServices,
string[] rgsServiceNames);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
private static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
[DllImport("rstrtmgr.dll")]
private static extern int RmEndSession(uint pSessionHandle);
[DllImport("rstrtmgr.dll")]
private static extern int RmGetList(uint dwSessionHandle,
out uint pnProcInfoNeeded,
ref uint pnProcInfo,
[In, Out] RM_PROCESS_INFO[] rgAffectedApps,
ref uint lpdwRebootReasons);
/// <summary>
/// Checks if a pkg has been locked by another user
/// </summary>
/// <param name="path">The pkg file path.</param>
/// <param name="includeCurrentUserProcesses">Check also for current user's processes</param>
/// <returns></returns>
public static bool AnotherUserIsLockingPkg(string path, bool includeCurrentUserProcesses = false)
{
uint handle;
string key = Guid.NewGuid().ToString();
Process currentProcess = Process.GetCurrentProcess();
int res = RmStartSession(out handle, 0, key);
if (res != 0)
throw new Exception("Could not begin restart session. Unable to determine file locker.");
try
{
const int ERROR_MORE_DATA = 234;
uint pnProcInfoNeeded = 0,
pnProcInfo = 0,
lpdwRebootReasons = RmRebootReasonNone;
string[] resources = new string[] { path }; // Just checking on one resource.
res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);
if (res != 0)
throw new Exception("Could not register resource.");
//Note: there's a race condition here -- the first call to RmGetList() returns
// the total number of process. However, when we call RmGetList() again to get
// the actual processes this number may have increased.
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);
if (res == ERROR_MORE_DATA)
{
// Create an array to store the process results
RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
pnProcInfo = pnProcInfoNeeded;
// Get the list
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
//pnProcInfo contains all the processes that are using the pkg
if (res == 0)
{
// Enumerate all of the results and check for waf3 process and not same session
for (int i = 0; i < pnProcInfo; i++)
{
try
{
if (includeCurrentUserProcesses)
{
if (processInfo[i].strAppName == currentProcess.ProcessName)
return true;
}
else
{
if (processInfo[i].strAppName == currentProcess.MainModule.ModuleName && processInfo[i].TSSessionId != currentProcess.SessionId)
return true;
}
}
// catch the error -- in case the process is no longer running
catch (ArgumentException)
{ }
}
}
else
throw new Exception("Could not list processes locking resource.");
}
else if (res != 0)
throw new Exception("Could not list processes locking resource. Failed to get size of result.");
}
finally
{
RmEndSession(handle);
}
return false;
}
#endregion
#区域检查其他用户的进程是否正在锁定pkg
[StructLayout(LayoutKind.Sequential)]
私有结构RM\u唯一\u进程
{
公共int-dwProcessId;
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
}
private const int rmrebootorreasonone=0;
私有常数int CCH\U RM\U MAX\U APP\U NAME=255;
私有const int CCH_RM_MAX_SVC_NAME=63;
//私有枚举RM_应用程序_类型
//{
//RmUnknownApp=0,
//RmMainWindow=1,
//RmOtherWindow=2,
//RmService=3,
//RmExplorer=4,
//RmConsole=5,
//RmCritical=1000
//}
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
私有结构RM\u进程\u信息
{
公共RM_唯一的流程;
[Marshallas(UnmanagedType.ByValTStr,SizeConst=CCH\u RM\u MAX\u APP\u NAME+1)]
公共字符串名称;
[Marshallas(UnmanagedType.ByValTStr,SizeConst=CCH\u RM\u MAX\u SVC\u NAME+1)]
公共字符串strServiceShortName;
//公共RM_应用程序类型应用程序类型;
公共应用状态;
公共uint TSSessionId;
[Marshallas(UnmanagedType.Bool)]
公共布尔布尔表;
}
[DllImport(“rstrtmgr.dll”,CharSet=CharSet.Unicode)]
专用静态外部RmRegisterResources(uint pSessionHandle,
UInt32文件,
字符串[]rgsFilenames,
UInt32应用程序,
[在]RM_唯一_流程[]RGA应用程序中,
UInt32 N服务,
字符串[]rgsServiceNames);
[DllImport(“rstrtmgr.dll”,CharSet=CharSet.Auto)]
私有静态外部int-RmStartSession(out-uint-pSessionHandle、int-dwSessionFlags、字符串stressionkey);
[DllImport(“rstrtmgr.dll”)]
私有静态外部内部RmEndSession(uint pSessionHandle);
[DllImport(“rstrtmgr.dll”)]
私有静态外部内部RmGetList(uint dwSessionHandle,
需要的输出单元pnprocinfo,
参考uint pnProcInfo,
[In,Out]RM_流程_信息[]rgAffectedApps,
参考单元LPDWREBOTREASOS);
///
///检查pkg是否已被其他用户锁定
///
///pkg文件路径。
///还要检查当前用户的进程
///
公共静态bool AnotherUserIsLockingPkg(字符串路径,bool includecurrentuserprocesss=false)
{
uint手柄;
字符串键=Guid.NewGuid().ToString();
Process currentProcess=Process.GetCurrentProcess();
int res=RmStartSession(输出句柄,0,键);
如果(res!=0)
抛出新异常(“无法开始重新启动会话。无法确定文件锁定程序。”);
尝试
{
const int ERROR\u MORE\u DATA=234;
uint pnProcInfoNeeded=0,
pnProcInfo=0,
lpdwRebootReasons=RmRebootReasonNone;
string[]resources=newstring[]{path};//只检查一个资源。
res=RmRegisterResources(handle,(uint)resources.Length,resources,0,null,0,null);
如果(res!=0)
抛出新异常(“无法注册资源”);
//注意:这里有一个竞争条件——对RmGetList()的第一个调用返回
//进程总数。但是,当我们再次调用RmGetList()以获取
//这一数字的实际进程可能有所增加。
res=RmGetList(handle,out pnProcInfoNeeded,ref pnProcInfo,null,ref lpdwrebootoreasons);
如果(res==错误\u更多\u数据)