C# Process.Start Causing AccessViolationException Randomly - c#

I have been tackling this issue for 3 months now.
Error I am Getting in Native Debugging:
"Exception thrown at 0x5A222FC2 (comct123.dll) in FileReader.exe:
0xC0000005: Access violation reading location 0x0000000C."
Normal Debug:
'System.AccessVioliationException' in System.Windows.Forms.dll
My setup is really simple:
public static Form_Interface Interface;
public static void Initialize()
{
Application.SetCompatibleTextRenderingDefault(false);
Interface = new Form_Interface();
Interface.Filesdgv.DataSource = File.SortableBindingList;
Application.Run(Interface);
}
Seems simple enough, right? No.
So basically I have a simple Event that simply opens the file using Process.Start() and no matter what I do it will randomly crash with 'System.AccessVioliationException' in System.Windows.Forms.dll here:
private void Filesdgv_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
Filesdgv.Invoke((Action)(() =>
{
try
{
int rowIndex = e.RowIndex;
if (rowIndex >= 0)
{
int columnIndex = e.ColumnIndex;
File file = (File)((DataGridView)sender).Rows[rowIndex].DataBoundItem;
switch (columnIndex)
{
case 0:
{
Process.Start(file.Location);
}
break;
}
}
}
catch
{
// This fking catch never works anyway.
}
}));
}
private void FileInterface_Load(object sender, EventArgs e)
{
foreach (string oCurrent in Directory.GetFiles(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "Files To Check")))
if (oCurrent.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
new File(oCurrent.Split('\\').Last(), oCurrent);
}
It doesn't matter if I am opening files/links or anything else, it still behaves in the same way.
The link and file location is a readonly field as well.
I have many other uses for reading row data and it never crashes, even if i spam click 10000 times, It will only crash randomly with Process.Start()
Things I tried:
Using BeginInvoke
Using Invoke
Not Using Invoke/BeginInvoke
Putting File Link into a string before reading it.
Using multiple Try Catch
Recoded on another machine... same results there aswell.
I tried using File.Open (either doesn't open the file or throws same error lmao)
Tried using [HandleProcessCorruptedStateExceptions], still won't catch the exception.
Dosen't matter if i click slow or fast still 1/30 chance it happens.
Tried Putting Task.Run(() => Process.Start()); you'd think that a thread will protect you from an exception? no still crashes...
File Class looks like this:
public class File
{
public static SortableBindingList<File> SortableBindingList = new SortableBindingList<File>(new List<File>());
public readonly string fileName;
public readonly string filePath;
public void AddRow()
{
Client.Interface.Invoke((Action)(() =>
{
lock (SortableBindingList)
if (!SortableBindingList.Contains(this))
SortableBindingList.Add(this);
}));
}
public string FileName
{
get
{
return fileName;
}
}
public string Location
{
get
{
return filePath;
}
}
public File(string fileName, string filePath)
{
this.fileName = fileName;
this.filePath = filePath;
AddRow();
}
}
Initalize() is called in static void Main(string[] args) btw.
There are no other threads running editing stuff or anything like that, the only thread running is the form thread. which waits for user input.
Solutions I am looking for:
Alternative Method to launch files/hyperlinks.
A way to avoid form crashing (try catch style)
Crashes even with static data!:
Other threads running although these were not started by me.

Task.Run(() =>
{
Thread.Sleep(100);
Process.Start("https://www.youtube.com");
});
This has fixed my issues, it seems that when trying to immediately run "process.start" during a click event, the GUI unfocusing + starting a new process the exact same moment causes an Exception. (Microsoft pls fix.)

Related

Prevent process seeing existing instance

Here's the situation.
I have an application which for all intents and purposes I have to treat like a black box.
I need to be able to open multiple instances of this application each with a set of files. The syntax for opening this is executable.exe file1.ext file2.ext.
If I run executable.exe x amount of times with no arguments, new instances open fine.
If I run executable.exe file1.ext followed by executable.exe file2.ext then the second call opens file 2 in the existing window rather than creating a new instance. This interferes with the rest of my solution and is the problem.
My solution wraps this application and performs various management operations on it, here's one of my wrapper classes:
public class myWrapper
{
public event EventHandler<IntPtr> SplashFinished;
public event EventHandler ProcessExited;
private const string aaTrendLocation = #"redacted";
//private const string aaTrendLocation = "notepad";
private readonly Process _process;
private readonly Logger _logger;
public myWrapper(string[] args, Logger logger =null)
{
_logger = logger;
_logger?.WriteLine("Intiialising new wrapper object...");
if (args == null || args.Length < 1) args = new[] {""};
ProcessStartInfo info = new ProcessStartInfo(aaTrendLocation,args.Aggregate((s,c)=>$"{s} {c}"));
_process = new Process{StartInfo = info};
}
public void Start()
{
_logger?.WriteLine("Starting process...");
_logger?.WriteLine($"Process: {_process.StartInfo.FileName} || Args: {_process.StartInfo.Arguments}");
_process.Start();
Task.Run(()=>MonitorSplash());
Task.Run(() => MonitorLifeTime());
}
private void MonitorLifeTime()
{
_logger?.WriteLine("Monitoring lifetime...");
while (!_process.HasExited)
{
_process.Refresh();
Thread.Sleep(50);
}
_logger?.WriteLine("Process exited!");
_logger?.WriteLine("Invoking!");
ProcessExited?.BeginInvoke(this, null, null, null);
}
private void MonitorSplash()
{
_logger?.WriteLine("Monitoring Splash...");
while (!_process.MainWindowTitle.Contains("Trend"))
{
_process.Refresh();
Thread.Sleep(500);
}
_logger?.WriteLine("Splash finished!");
_logger?.WriteLine("Invoking...");
SplashFinished?.BeginInvoke(this,_process.MainWindowHandle,null,null);
}
public void Stop()
{
_logger?.WriteLine("Killing trend...");
_process.Kill();
}
public IntPtr GetHandle()
{
_logger?.WriteLine("Fetching handle...");
_process.Refresh();
return _process.MainWindowHandle;
}
public string GetMainTitle()
{
_logger?.WriteLine("Fetching Title...");
_process.Refresh();
return _process.MainWindowTitle;
}
}
My wrapper class all works fine until I start providing file arguments and this unexpected instancing behaviour kicks in.
I can't modify the target application and nor do I have access to its source to determine whether this instancing is managed with Mutexes or through some other feature. Consequently, I need to determine if there is a way to prevent the new instance seeing the existing one. Would anyone have any suggestions?
TLDR: How do I prevent an application that is limited to a single instance determining that there is already an instance running
To clarify (following suspicious comments), my company's R&D team wrote executable.exe but I don't have time to wait for their help in this matter (I have days not months) and have permission to do whatever required to deliver the required functionality (there's a lot more to my solution than this question mentions) swiftly.
With some decompiling work I can see that the following is being used to find the existing instance.
Process[] processesByName = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
Is there any way to mess with this short of creating multiple copies of the application with different names? I looked into renaming the Process on the fly but apparently this isn't possible short of writing kernel exploits...
I have solved this problem in the past by creating copies of the source executable. In your case, you could:
Save the 'original.exe' in a specific location.
Each time you need to call it, create a copy of original.exe and name it 'instance_xxxx.exe', where xxxx is a unique number.
Execute your new instance exe as required, and when it completes you can delete it
You could possibly even re-use the instances by creating a pool of them
Building on Dave Lucre's answer I solved it by creating new instances of the executable bound to my wrapper class. Initially, I inherited IDisposable and removed the temporary files in the Disposer but for some reason that was causing issues where the cleanup would block the application, so now my main program performs cleanup at the end.
My constructor now looks like:
public AaTrend(string[] args, ILogger logger = null)
{
_logger = logger;
_logger?.WriteLine("Initialising new aaTrend object...");
if (args == null || args.Length < 1) args = new[] { "" };
_tempFilePath = GenerateTempFileName();
CreateTempCopy(); //Needed to bypass lazy single instance checks
HideTempFile(); //Stops users worrying
ProcessStartInfo info = new ProcessStartInfo(_tempFilePath, args.Aggregate((s, c) => $"{s} {c}"));
_process = new Process { StartInfo = info };
}
With the two new methods:
private void CreateTempCopy()
{
_logger?.WriteLine("Creating temporary file...");
_logger?.WriteLine(_tempFilePath);
File.Copy(AaTrendLocation, _tempFilePath);
}
private string GenerateTempFileName(int increment = 0)
{
string directory = Path.GetDirectoryName(AaTrendLocation); //Obtain pass components.
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(AaTrendLocation);
string extension = Path.GetExtension(AaTrendLocation);
string tempName = $"{directory}\\{fileNameWithoutExtension}-{increment}{extension}"; //Re-assemble path with increment inserted.
return File.Exists(tempName) ? GenerateTempFileName(++increment) : tempName; //If this name is already used, increment an recurse otherwise return new path.
}
Then in my main program:
private static void DeleteTempFiles()
{
string dir = Path.GetDirectoryName(AaTrend.AaTrendLocation);
foreach (string file in Directory.GetFiles(dir, "aaTrend-*.exe", SearchOption.TopDirectoryOnly))
{
File.Delete(file);
}
}
As a side-note, this approach will only work for applications with (lazy) methods of determining instancing that rely on Process.GetProcessByName(); it won't work if a Mutex is used or if the executable name is explicitly set in the manifests.

Getting unexpected crash reports inside a try-catch block

I'm using HockeyApp to collect crash data for my app, but for some reason it doesn't provide the stack trace.
What I have is something like that:
MyNamespace!<BaseAddress>+0x5d1287
MyNamespace!<BaseAddress>+0x5f18d5
MyNamespace!<BaseAddress>+0x5f1827
Microsoft.HockeyApp.Extensibility.Windows.UnhandledExceptionTelemetryModule.CoreApplication_UnhandledErrorDetected(Object sender, ApplicationModel.Core.UnhandledErrorDetectedEventArgs e)
so it's kinda hard to find out what's happening.
The exception message is helpful tho, as it says
Element not found. Cannot find credential in Vault
and there's just one place in which I'm using PasswordVault.
The problem here is that I'm using it inside a try/catch block, so I really don't understand why I'm getting this report, and I can't even reproduce it.
This is the full PasswordVaultService class, so that you can see exactly what I'm doing.
public class PasswordVaultService
{
private static readonly PasswordVault Vault = new PasswordVault();
public static string RetrieveSecret(Entry entry)
{
try
{
var results = Vault.FindAllByResource(entry.Name);
if (results.Count == 0) return null;
var result = results[0];
result.RetrievePassword();
return result.Password;
}
catch (Exception)
{
return null;
}
}
public static void StoreSecret(Entry entry, string secret)
{
Vault.Add(new PasswordCredential(entry.Name, entry.Name, secret));
}
public static void DeleteSecret(Entry entry)
{
var results = Vault.FindAllByResource(entry.Name);
if (results.Count == 0) return;
var result = results[0];
Vault.Remove(result);
}
}
I've been getting this error for some time now, and I don't understand what's going on because the class is quite simple. Before posting I've even searched for Vault inside the project and this is the only place where I'm using the PasswordVault.

Save file from Richtextbox using Invoke

I am having a RichTextbox and I am trying to save file using
public bool SaveNote(string path)
{
try
{
_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText);
return true;
}
catch
{
return false;
}
}
It was working fine until I started working with background worker thread. Now this method is being called from background worker and now I am receiving an error as
Cross-thread operation not valid: Control 'rtbContent' accessed from a thread other than the thread it was created on.
I think we have to invoke it using _rtbContent.Invoke but failing to get the syntax correct. What I tried was
if(_rtbContent.InvokeRequired)
_rtbContent.Invoke(new MethodInvoker(_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText)));
Here I am getting Method name expected compilation error on _rtbContent.SaveFile(path, RichTextBoxStreamType.RichText).
I am not very comfortable in using these threads but has recently started working on them. Can anyone help me on this issue?
Use a callback:
delegate void SaveNoteCallback(string path);
public void SaveNote(string path)
{
if(_rtbContent.InvokeRequired)
{
SaveNoteCallback d = new SaveNoteCallback(SaveNote);
this.Invoke(d, new object[] {path});
}
else
{
_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText);
}
}
I got another interesting solution and would like to post that.
public void SaveNote(string path)
{
if(_rtbContent.InvokeRequired)
{
_rtbContent.Invoke(new MethodInvoker(delegate{_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText}));
//Below is also same as above
//_rtbContent.Invoke(new MethodInvoker(()=>_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText)));
}
else
{
_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText);
}
}
I think it is much clean solution. Hope it helps.

Shared Variable between Watin ApartmentState.STA Thread and parent Thread?

I'm trying to get Watin working in my SSIS script Task to do some automation by opening IE in a new thread, do something, find the final value and basically return/set that value in the parent thread.
So I have this for now:
public partial class TestWatin{
public void Main()
{
String finalValueFromWeb = "";
Thread runnerThread = new Thread(delegate() { getDAFValue(ref finalValueFromWeb ); });
runnerThread.ApartmentState = ApartmentState.STA;
runnerThread.Start();
runnerThread.Join();
MessageBox.Show(finalValueFromWeb);
//here i want to use the value of finalValueFromWeb to download a file
//but if i try to access finalValueFromWeb the process would fail.
}
//do the Watin stuff here
public void findHiddenURL(String refObject)
{
//setup page controls, press search, grab the value of "hiddenURL"
IE ie = new IE("some_webadress_to_go_to");
ie.Visible = false;
ie.SelectList("testID1").Option("Car").Select();
ie.SelectList("testID2").Option("JAP").Select();
ie.SelectList("testID3").Option("2012").Select();
ie.Button("testSearch").Click();
Link link = ie.Link("hiddenURL");
ie.Close();
//fails here?
refObject = link.Url;
}
}
What I basically want to is for findHiddenURL() to find me a value which is a string containing some CSV url. I then want to use that string to download the CSV and process it.
The problem is when I try to set the value of finalValueFromWeb inside findHiddenURL() where the process fails. The Exception message says The Object Reference is not set to an instance of an object
Can someone please tell me how I should be going about this problem? What is the proper way of doing this type of thing? Thanks
Make the variable a member of the class and try to lock it. You can use c# lock :
http://msdn.microsoft.com/en-us/library/c5kehkcz%28v=vs.71%29.aspx
protected string finalValueFromWeb ;
....
public void Main()
{
...
lock(finalValueFromWeb)
{
MessageBox.Show(finalValueFromWeb);
}
}
public void findHiddenURL(String refObject)
{
...
lock(finalValueFromWeb)
{
finalValueFromWeb = link.Url;
}
}

What's wrong with my application ---- Size was 0, but I expected 46806 !

I'm a C# programmer.
Now, I'm using the ICSharpCode.SharpZipLib.dll to create a zip file in my current project. But it occurs to me that when I click the button at the SECOND TIME to execute a function to create a zip file, the application will throw an exception, friendly and seriously told me that "Size was zero, but I expected 46086".
I'm so confused that I want to know why? When I click the button at the first time, I can do it successfully without any error.
My related codes are as follows:
internal void ThreadProc()
{
try
{
ZipHelper.CreateZip(backupZipFile, Constants.HomeConstant, true);
// do other things
}
}
The CreateZip() function's realization is as follows:
public static void CreateZip(string zipFileName, string sourceDirectory, bool recurse)
{
FastZip zip = new FastZip();
if (File.Exists(zipFileName))
{
File.Delete(zipFileName);
}
zip.CreateZip(zipFileName, sourceDirectory, true, "");
}
Now, I will show you the recursive calling process:
Call method "UpdateAppAsync" in "ActiveCheckManager" class
public void UpdateAppAsync(string masterConfig)
{
this.masterConf = masterConfig;
Thread actualThread = new Thread(new ThreadStart(UpdateApp));
actualThread.IsBackground = true;
actualThread.CurrentCulture = Thread.CurrentThread.CurrentCulture;
actualThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
actualThread.Start();
}
Call the UpdateApp function asynchronously, in the UpdateApp method, it will only call the UpdateDetail function simply.
private void UpdateDetail(string masterConfig, string category)
{
IUpdate worker = new HP.ActiveCheckLocalMode.UpdateEngine.UpdateManager();
worker.UpdateApp(masterConf);
}
The worker.UpdateApp will call UpdateDetail(string, UpdateCategory) only.
private void UpdateDetail(string masterConfig, UpdateCategory cat)
{
UpdateThread updateThread = new UpdateThread(this, cat);
updateThread.MasterConfig = masterConfig;
updateThread.ThreadProc();
}
That is the calling process. When I click the update button second time, it will throw an exception, can you help me? Thank you very much.
Has the first task thread finished before you start the second time?
I would imagine that File.Delete() and some items in the SharpZipLib to not respond nicelly to multithreadingly zip the same folder simultaneously to the same file.
Promote that " UpdateThread updateThread " as a private member of the "ActiveCheckManager" class, then check if it is already running from a previous click before creating a new thread.

Categories