I am developing a c# application, backend as sqlite.In my application i have an option for clean databse.It means the curren .db file will delete using File.Delete method and again it create empty databse using File.create method.Now let me explain the problem.
To perform cleandatabse task, i have to stop all the process which is running ,after doing that if i click on clean database it is throwing an error that file cannot delete, it is being used by another process.i am able to stop all the thread which is running.
Somehow i am able to find which process is blocikng the file ,
foreach (var process in Process.GetProcesses()) {
var files = GetFilesLockedBy(process);
if (files.Contains(filePath))
{
procs.Add(process);
Console.WriteLine(process.ProcessName);
process.Kill();
File.Delete(filePath);
}
}
But in the above code i used process.Kill, which close the window form which i am running.
without using kill, i tried close and dispose which doesn't work for me.
Can you please help me to release the file from the process without closing the application and then yo delete the db file.
Thank you in advance
Best regards
Sangita.
You should make sure you close every stream you open it:
using (Stream str = File.Create("C:\\h.txt"))
{
// your code here
} // the stream will be automatically closed here
if you don't put this using statement, it will cause you a lot of bugs, even if you close it manually str.Close();
Streamss are disposable types, you must manage their lifetime manually, either by that using syntax, e.g.:
using (StreamReader f = new ...) {
}
... or by doing it more verbosely (this syntax is required if you allocate and delete the Stream in different code-blocks/functions):
try {
StreamReader f = new ...;
...
} finally {
if (null != f) f.Dispose();
}
... or by making the holding class an IDisposable by itself. See also What Your Mother Never Told You About Resource Deallocation.
Interestingly, this seems to be a practical incarnation of one of those https://stackoverflow.com/questions/2245196/c-urban-myths/2245382#2245382 :
0) In C++, you must mess around with pointers, that's old and dangerous, use C#
Gee, #include boost/shared_ptr> or one of the like. Actually, it is often easier to produce mess in your sowonderful C#:
static void Main () {
foo();
bar();
}
static void foo () {
var f = new StreamWriter ("hello.txt");
f.Write ("hello world");
}
static void bar () {
var f = new StreamReader ("hello.txt");
Console.WriteLine (f.ReadToEnd ());
}
"Unhandled IOException: The process cannot access the file 'hello.txt' because it is being used by another process."
Those claims, btw, are often made by those who happen to never have heard of RAII, and about how far you can get without even smart-pointers.
Not sure but you may be calling Kill on the current process.
EDIT : call Delte after the loop.
Try this :
int currentProcessId = Process.GetCurrentProcess().Id;
foreach (var process in Process.GetProcesses()) {
if (process.Id != currentProcessId)
{
var files = GetFilesLockedBy(process);
if (files.Contains(filePath))
{
procs.Add(process);
Console.WriteLine(process.ProcessName);
process.Kill();
}
}
}
File.Delete(filePath);
Moreover Close doesn't terminate the process, you have to call CloseMainWindow or Kill.
Related
I want to write a file of about 10 million rows. I'm using StreamWriter with a using statement, however it seems that the StreamWriter is not flushing. Here is my code:
public void ExportRecords(IEnumerable<Record> records, string path)
{
using(TextWriter writer = new StreamWriter(path))
{
writer.WriteLine("header");
foreach(var record in records)
{
string line = "";
//Fill line with record properties
writer.WriteLine(line);
}
}
}
At a certain line the StreamWriter doesn't add any rows. So where is the issue?
EDIT
As mentioned is the comments the code is run async.
Here is how it is:
Task.Run(() =>
{
if (!String.IsNullOrEmpty(folderPath))
{
var records = _generator.GenerateData();
_dataService.ExportRecords(records, $"{folderPath}/RECORDS.csv");
//Just a message box
_reporter.ReportMessage($"Generation and exportation finished");
}
else
{
IsGenerating = false;
_reporter.ReportMessage("No output file was created");
}
});
So I did put a breaking point to check if the method starts executing, and it does. I'm just indicating the the code is not stuck in generation method.
Change temporarily the type of your application to Console Application (if it is Windows Application), and add some Console.WriteLine at strategic points so that you have some feedback about the progress of the procedure. Even better you could add logging to your application, using a library like log4net or Serilog. It will be useful in the production phase of your application too, not only in the development/debugging phase.
Flush() has to be manually called at some point if you need it in the middle of the operation, otherwise the stream will only be flushed at the end of the statement, when it is disposed.
I'm currently working on a simple converter tool and was wondering if it's possible to make the application close if I run the .exe again. Some kind of "if two instances run -> close both".
I need this function because I run the application via a shortcut-button inside a third party program. So I would like if my converter app closes once I press this shortcut-button again.
I know it sounds counter intuitive running the exe again to close, but i have to have my app work the same way as the integrated tools in the third party program, and this involves opening and closing tools by pressing their respective toggle-buttons. I can't add a plug-in running inside the third party program, but i CAN add a shortcut button next to the integrated tools. It's a work around, but it will at least act like a toggle button.
You could do something like this:
Process currentProcess = Process.GetCurrentProcess();
bool suocide = false;
foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName))
{
if (process.MainModule.FileName == currentProcess.MainModule.FileName && process.Id != currentProcess.Id)
{
process.CloseMainWindow();
process.Close();
//process.Kill(); or you can do kill instead
suocide = true;
}
}
if (suocide)
currentProcess.Kill(); // you probably don't care about new process as it is just for closing purpose but if you do then do a proper application exit
You can put it inside your window constructor.
Step 1 Identify a 2nd instance:
I'd recommend the MUTEX answer in this question:
How can I prevent launching my app multiple times?
Step 2 Get that first instance closed
Although the MUTEX answer identifies a second instance, it gives no way to find it and tell it to close.
Solution: Listen with a named pipe in the app (first instance the ClosEE):
//using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public static class SomeClass
{
public static void SomeMethod()
{
Threading.Thread t = new Threading.Thread(() =>
{
try {
while (true) {
dynamic server = new NamedPipeServerStream("Closer", PipeDirection.InOut, -1);
server.WaitForConnection();
if (!server.IsConnected)
return;
dynamic reader = new IO.StreamReader(server);
dynamic casetxt = reader.ReadToEnd();
server.Close();
RootForm.Invoke(() =>
{
if (casetxt == "End") {
System.Environment.Exit(0);
}
});
}
} catch (Exception ex) {
// try/catch required in all child threads as error silently ends app.
// log it...
}
});
t.IsBackground = true;
t.Name = "EnderListener";
t.Start();
}
}
//=======================================================
//Service provided by Telerik (www.telerik.com)
Then when you detect a second instance via the Mutex, send this message from the 2nd instance the "Closer":
dynamic serverloopcount = 1;
dynamic iteration = 1;
dynamic GotServerCount = false;
do {
NamedPipeClientStream client = new NamedPipeClientStream("Closer");
client.Connect();
if (!GotServerCount) {
GotServerCount = true;
serverloopcount = client.NumberOfServerInstances;
}
dynamic reader = new IO.StreamReader(client);
dynamic writer = new IO.StreamWriter(client);
writer.WriteLine("End");
writer.Flush();
writer.Close();
client.Close();
iteration += 1;
} while (iteration <= serverloopcount);
Good luck.
I am using visual studio 2010 and I am having a .DWG file which I want to open in autocad. Till now I have used this.
Process p = new Process();
ProcessStartInfo s = new ProcessStartInfo("D:/Test File/" + fileName);
p.StartInfo = s;
p.Start();
But what I want is to close the file inside the Autocad but not the autocad itself. (Means atocad.exe should be kept running).
Till now I hve used this but its closing the acad.exe not the file.
foreach (Process Proc in Process.GetProcesses())
{
if (Proc.ProcessName.Equals("acad"))
{
Proc.CloseMainWindow();
Proc.Kill();
}
}
Take the Autocad .NET libraries from Autodesk Sites (http://usa.autodesk.com/adsk/servlet/index?id=773204&siteID=123112)
Then you will be able to use Application and Document classes.
They will give you full control over opening and closing documents within the application.
You can find many articles on that, and can ask further questions.
AutoCAD does have an api. there are 4 assemblys. Two for in-process and two for COM.
inprocess :
acdbmgd.dll
acmgd.dll
COMInterop :
Autodesk.Autocad.Interop.dll
Autodesk.Autocad.Interop.Common.dll
this is a method that will open a new instance of AutoCAD or it will connect to an existing running instance of AutoCAD.
you will need to load these .dlls into your project references.
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
namespace YourNameSpace {
public class YourClass {
AcadApplication AcApp;
private const string progID = "AutoCAD.Application.18.2";// this is AutoCAD 2012 program id
private string profileName = "<<Unnamed Profile>>";
private const string acadPath = #"C:\Program Files\Autodesk\AutoCAD 2012 - English\acad.exe";
public void GetAcApp()
{
try
{
AcApp = (AcadApplication)Marshal.GetActiveObject(progID);
} catch {
try {
var acadProcess = new Process();
acadProcess.StartInfo.Arguments = string.Format("/nologo /p \"{0}\"", profileName);
acadProcess.StartInfo.FileName = (#acadPath);
acadProcess.Start();
while(AcApp == null)
{
try { AcApp = (AcadApplication)Marshal.GetActiveObject(progID); }
catch { }
}
} catch(COMException) {
MessageBox.Show(String.Format("Cannot create object of type \"{0}\"",progID));
}
}
try {
int i = 0;
var appState = AcApp.GetAcadState();
while (!appState.IsQuiescent)
{
if(i == 120)
{
Application.Exit();
}
// Wait .25s
Thread.Sleep(250);
i++;
}
if(AcApp != null){
// set visibility
AcApp.Visible = true;
}
} catch (COMException err) {
if(err.ErrorCode.ToString() == "-2147417846"){
Thread.Sleep(5000);
}
}
}
}
}
closeing it is as simple as
Application.Exit();
and forgive the code. its atrocious, this was one of my first methods when i just started developing...
I doubt you will be able to do this unless AutoCAD has an API that you can hook into and ask it to close the file for you.
Your c# app can only do things to the process (acad.exe) , it doesn't have access to the internal operations of that process.
Also, you shouldn't use Kill unless the process has become unresponsive and certainly not immediately after CloseMainWindow.
CloseMainWindow is the polite way to ask an application to close itself. Kill is like pulling the power lead from the socket. You aren't giving it the chance to clean up after itself and exit cleanly.
There is one other possibility - this will only work if your C# code is running on the same machine as the AutoCAD process and it is not really recommended, but, if you are really stuck and are prepared to put up with the hassle of window switching you can send key strokes to an application using the SendKeys command.
MSDN articles here:
http://msdn.microsoft.com/EN-US/library/ms171548(v=VS.110,d=hv.2).aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx
Using this you could send the key strokes to simulate the user using the menu commands to close the file.
To perform the closing of file, best way out is to follow the steps at this ObjectARX SDK for c# and change the following code with the below code.
[CommandMethod("CD", CommandFlags.Session)]
static public void CloseDocuments()
{
DocumentCollection docs = Application.DocumentManager;
foreach (Document doc in docs)
{
// First cancel any running command
if (doc.CommandInProgress != "" &&
doc.CommandInProgress != "CD")
{
AcadDocument oDoc =
(AcadDocument)doc.AcadDocument;
oDoc.SendCommand("\x03\x03");
}
if (doc.IsReadOnly)
{
doc.CloseAndDiscard();
}
else
{
// Activate the document, so we can check DBMOD
if (docs.MdiActiveDocument != doc)
{
docs.MdiActiveDocument = doc;
}
int isModified =
System.Convert.ToInt32(
Application.GetSystemVariable("DBMOD")
);
// No need to save if not modified
if (isModified == 0)
{
doc.CloseAndDiscard();
}
else
{
// This may create documents in strange places
doc.CloseAndSave(doc.Name);
}
}
}
I am trying to prevent opening help file more than once.
This is the method I am using:
public void openHelp()
{
int count = 0;
string helpPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + #"\MyApp\Help\eHelp.chm";
System.Diagnostics.Process[] helpProcs = System.Diagnostics.Process.GetProcesses();
foreach (System.Diagnostics.Process proc in helpProcs)
{
if (proc.MainWindowTitle == "Sample App Help")
{
count++;
}
}
if (count == 0)
{
System.Diagnostics.Process.Start(helpPath);
}
else
{
}
}
The idea is, if you find the process with the same MainWindowTitle, then do not start a new one.
However, this is not reliable. In some cases it still starts the process, even though one is already running. Is there an issue with a logic?
Thank you.
P.S. Of course the MainWindowTitle is "Sample App Help", at least that is what I see while debugging.
Update:
Issue only occurs when user has minimised help file. So I suspect something happens in the system and I need to check something. Any suggestions?
The Remarks section in Process.MainWindowTitle contains the following note:
The main window is the window that currently has the focus; note that
this might not be the primary window for the process. You must use the
Refresh method to refresh the Process object to get the current main
window handle if it has changed.
Could this perhaps be the cause of your problem?
What about keeping the process id of a newly started help viewer and before starting another one, just check if the old one is still alive.
int id = ...
try
{
var proc = Process.GetProcessById(id);
}
catch
{
// no process running with that id
}
I have a method in my windows service as follows:
System.IO.File.Copy(path, ConfigurationManager.AppSettings["BulkInsertGiftRegisterCreatorDirectory"] + System.IO.Path.GetFileName(path));
Loyalty.Entity.Base.FileInfo file = new Loyalty.Entity.Base.FileInfo();
file.FileName = path;
request.Object = file;
ResponseBase response = new ResponseBase(request);
RequestConnection connection = new RequestConnection("cn");
FileManager fileManager = new FileManager(request, connection);
response = fileManager.OfflineGiftRegisterBulkInsert();
System.IO.File.Delete(ConfigurationManager.AppSettings["BulkInsertGiftRegisterCreatorDirectory"] + System.IO.Path.GetFileName(path));
// here is the part of stored procedure that uses file
SELECT #SCRIPT= 'BULK INSERT GIFT_CARD.GIFT_TEMP'
+' FROM '''
+ #FILE_PATH
+''' WITH ('
+'FIELDTERMINATOR = '','','
+ 'KEEPNULLS'
+');'
I can delete the file from file system by hand, but this code says me "Ooops! System.IO.IOException: The process cannot access the file 'filename'
because it is being used by another process."
I've searched the similar questions on stackoverflow and else where. But I could not find anything to help me. Copy or Delete methods return void and I have no stream in my code to dispose.
How can I fix it?
Thanks in advance.
Here is a method for you to check if a file is in use:
public static System.Boolean FileInUse(System.String file)
{
try
{
if (!System.IO.File.Exists(file)) // The path might also be invalid.
{
return false;
}
using (System.IO.FileStream stream = new System.IO.FileStream(file, System.IO.FileMode.Open))
{
return false;
}
}
catch
{
return true;
}
}
Also, to wait for a file I have made:
public static void WaitForFile(System.String file)
{
// While the file is in use...
while (FileInUse(file)) ; // Do nothing.
}
I hope this helps!
Before you go looking through the code you might want to use process explorer to Identify what process has the handle. This might rule out some issue you haven't thought of
update
Since you are using a timer you must make sure that your method is reentrant and you don't have any race conditions.. E.g. the timer ticks faster than you can process the event.
See this question
And this answer
Even better solution, is to add this two lines of code before using the function FileInUse that Vercas showed:
GC.Collect();
GC.WaitForPendingFinalizers();