Windows: Delete EXE after execution - c#

I am working on an application in C# which does the following things:
Write an EXE to disk
Execute the EXE through Process.Start()
I am now trying to ensure that the EXE will be deleted once it is closed.
The easiest way to do so is to set the FileOptions.DeleteOnClose parameter when creating the EXE using File.Create.
However, this means that the EXE can not be executed while is in use. Once the file handle is closed, the EXE is immediately deleted before it can be executed.
Is there any way to retain a "weak reference" to the EXE in my application which does not lock the file and allows it to be executed? Alternatively, is there any way to unlock the EXE for execution with the file handle still open? Are there any other obvious solutions I am missing?
CLARIFICATION A: I am aware of other methods to delete files in use which will delete the file eventually (e.g. upon reboot). I am however looking for a method to delete the file immediately once it starts executing which is handled by the OS (e.g. when running a batch that first executes the file and then deletes it, the file would remain on disk if the batch job is terminated).
CLARIFICATION B: To explain the bigger picture: The application receives and decrypts an executable file. After decryption, the file should be executed. However, I want to make sure the decrypted version of the EXE does not stay on disk. Ideally, I also want to prevent users from copying the decrypted EXE. However, since the decryption application runs as the same user, this will be impossible to achieve in a truly secure fashion as both have the same privileges on the system.

You could use Process.WaitForExit:
var process = Process.Start(processPath);
process.WaitForExit();
// File.Delete(processPath); // Not strong enough (thanks to Binary Worrier)
DeleteOrDie(processPath); // Will attempts anything to delete the file.
But it gives the possibility to copy the exe from where you writed it.
A good solution is to run it from memory.
If your target exe is a CLR program, you can use the Assembly.Load function:
// read the file and put data in bin
...
Assembly a = Assembly.Load(bin);
MethodInfo method = a.EntryPoint;
if (method == null) throw new NoEntryPointException();
object o = a.CreateInstance(method.Name);
method.Invoke(o, null);
More details here.
If you want to load/execute any exe in memory, you could use the Nebbett’s Shuttle approach but you will need to code it in C/C++ and make a call to it from C#.
Also it looks like Microsoft doesn't like it (security issues) and I don't think you can achieve it from C# only. Good anti-virus will probably detect it.

In a not very good way but a way that can give you what you want, I suggest this solution:
(I use a Console Application with some input arguments for this solution)
[1: ] Write a function to check opened processes:
/// <summary>
/// Check application is running by the name of its process ("processName").
/// </summary>
static bool IsProcessOpen(string processName)
{
foreach (Processing.Process clsProcess in Processing.Process.GetProcesses())
{
if (clsProcess.ProcessName.ToUpper().Contains(processName.ToUpper()))
return true;
}
return false;
}
[2: ] Define some variables:
static bool IamRunning = true;
static int checkDuration = 1; // in seconds
[3: ] Use a Thread for run a loop for checking:
Thread t = new Thread(delegate() {
DateTime lastCheck = DateTime.MinValue;
while (IamRunning)
{
var now = DateTime.Now;
int dd = (now.Hour - lastCheck.Hour) * 3600 + (now.Minute - lastCheck.Minute) * 60 + now.Second - lastCheck.Second;
if (dd >= checkDuration)
if (!IsProcessOpen("ProcessName"))
{
delApplication(); // You have a function to delete ...
break;
}
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
[4: ] Use a loop at the end of the program:
while (t.ThreadState == ThreadState.Running)
{
// just wait.
}
Note: This solution by Console Application in my low computer have 50% usage of CPU.

Related

Can I redirect output from a C DLL into my c# log4net output

I have a C# application which in turn loads a C or C++ dll (which in turn loads other C/C++ dlls). Within the C# application I use a log4net logger to capture all the output into a series of log files. My application runs as a windows service so there is no console/output window for normal printfs or output written into stdout/stderr to go to.
Is there a way to setup the C# application to direct stdout/stderr (from the DLLs) and turn each line into a log4net output. Or is there some way within the C/C++ DLL to connect the stdout/stderr streams to the log4net output?
I found some solution (here : http://bytes.com/topic/c-sharp/answers/822341-dllimport-stdout-gets-eaten) that indicated I needed to put a call into my C DLL like this : setvbuf(stdout, NULL, _IONBF, 0); Though, I don't know what that does, it doesn't do what I want. I assume I'd also need a similar line for stderr. In either case, google seemed to think those lines simply take care of buffering and not redirection into log4net.
I assume I need some sort of function override which snags the console writes (from a loaded DLL in another language) and converts them into mLog.InfoFormat("{0}", consoleString); sorts of calls. I'm new to c# and not even sure what terms to google in order to find such an override (if its even possible).
Not sure if this complicates the problem, but my C# application is multithreaded and some of the DLLs have multiple threads as well. I assume that just means I need a lock of some sort inside the method that handles the console output and writes it into the log4net framework(maybe) or maybe the normal serialization of log4net will handle it for me.
Turns out those did the trick once I figured out how to use them. I setup two named pipes(or two ends of the same pipe?). One I connected to stdout and had it do a log message in log4net of whatever came through the pipe.
internal static void InfoLogWriter(Object threadContext)
{
mLog.Info("InfoLogWriterthread started");
int id = Process.GetCurrentProcess().Id; // make this instance unique
var serverPipe = new NamedPipeServerStream("consoleRedirect" + id, PipeDirection.In, 1);
NamedPipeClientStream clientPipe = new NamedPipeClientStream(".", "consoleRedirect" + id, PipeDirection.Out, PipeOptions.WriteThrough);
mLog.Info("Connecting Client Pipe.");
clientPipe.Connect();
mLog.Info("Connected Client Pipe, redirecting stdout");
HandleRef hr11 = new HandleRef(clientPipe, clientPipe.SafePipeHandle.DangerousGetHandle());
SetStdHandle(-11, hr11.Handle); // redirect stdout to my pipe
mLog.Info("Redirection of stdout complete.");
mLog.Info("Waiting for console connection");
serverPipe.WaitForConnection(); //blocking
mLog.Info("Console connection made.");
using (var stm = new StreamReader(serverPipe))
{
while (serverPipe.IsConnected)
{
try
{
string txt = stm.ReadLine();
if (!string.IsNullOrEmpty(txt))
mLog.InfoFormat("DLL MESSAGE : {0}", txt);
}
catch (IOException)
{
break; // normal disconnect
}
}
}
mLog.Info("Console connection broken. Thread Stopping.");
}
Also have a function to push all that to another thread so it doesn't block my main thread when it hits the various blocking calls.
internal static void RedirectConsole()
{
mLog.Info("RedirectConsole called.");
ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(InfoLogWriter));
// TODO enqueue and item for error messages too.
}
I'm having trouble with it disconnecting and have to reconnect the pipes, but I'll figure out a reconnect solution. I'm guessing that happens when DLLs get swapped back out of memory or perhaps when I need to read but there isn't anything currently ready to be read? I've also got to setup another pair to snag stderr and redirect it as well, using Error logs for that one. Probably want to get rid of the magic number (-11) and use the normal enums as well (STD_ERROR_HANDLE, etc)

Many threads, one method fails

My application is System Tray Application, using C#, .NET 4.0.
I'm trying to display many PDF files at a time and each PDF should split screen with other window, that I determine by ProcessName, that's all.
The difficulty is that I need to wait until user closes that window (.WaitForExit() method), because later I'm deleting PDF file. And here problem comes.
In first thread everything goes fine but the problem is when i try to show second PDF file window processList[0] THOUGH MoveWindow function returns true, and handle to that window is also correct only pdf window is resizing, the other window fails.
In main method the only thread that I'm creating (I call this piece of code couple of times, everytime user want to see pdf file):
Thread pdfThread = new Thread(() => ShowPdfFile(fullPath));
pdfThread.Start();
Then (simplified code)
public static void ShowPdfFile(string fileName)
{
try
{
Process pdfProcess = Process.Start(fileName);
Thread.Sleep(500);
string windowTitle = GetActiveWindowTitle();
IntPtr pdfHandle = (IntPtr)FindWindow(null, windowTitle);
MoveWindow(pdfHandle, 0, 0, 0, 0, true);
Process[] processList = Process.GetProcessesByName("someProcess");
MoveWindow(processList[0].MainWindowHandle, 0, 0, 0, 0, true);
pdfProcess.WaitForExit();
MoveWindow(processList[0].MainWindowHandle, 0, 0, max, max, true);
}
catch (Exception ex)
{
LogToFile(ex);
}
finally
{
try
{
File.Delete(fileName);
}
catch
{
LogToFile("Cannot delete file");
}
}
UPDATE: Well, I was debugging it whole day but just now i note that on second thread it doesn't wait on line pdfProcess.WaitForExit();
What should I change to force thread to wait for that exact pdfProcess exit?
There is a basic problem to your usage:
You start the external PDF application for each file. However this doesn't ensure that you have more than one process.
For example Acrobat reader only starts a single process. Additional files will just be "added" as new windows to the first process (You can check this by trying to manually open Acrobat reader twice --> won't work).
So in short: If you cannot control which PDF reader is used (and can ensure that you have a single process for EACH file) your approach will not work.
Note: Theoretically it would be possible to wait until the user closes the "reader window" that contains the specific file. However I strongly advise against this:
Looking up a window in a different process is very error prone (unless the process is explicitly designed in such a way...)
The solution would again depend on the reader application (you cannot be sure that Acrobat and Nitro use similar architecture to just name two readers)
Principally, if this feature is very important, you should consider to buy a PDF viewer component that allows to show the PDF's as windows of your own process.
Edit
The reason that the second thread isn't waiting is that the functionality to "add" a file to the first process uses a temporary process:
Temporary process is started for new file
Temporary process checks if the application is already running
Temporary process notifies the first process to open the specific file
Temporary process shuts down.
So waiting for that process will return almost immediately since the process in question already has stopped (or will stop in just a couple of milliseconds).
Daniel is right, however I found a solution! Here, maybe someone will use it.
Small comment: We must use winapi solutions instead of .WaitForExit().
The most important part is while loop, that waits for close pdf window.
Remember that FindWindow() and IsWindow() methods are from user32.dll (winapi).
This code run process based on it's paths, then gets it's handle and wait for it's closure.
Process pdfProcess = new Process();
pdfProcess.StartInfo.FileName = filePath;
if (pdfProcess.Start())
{
Thread.Sleep(500);
Process[] processlist = Process.GetProcesses();
string windowTitle = string.Empty;
foreach (Process process in processlist)
{
if (!String.IsNullOrEmpty(process.MainWindowTitle) && process.MainWindowTitle.Contains(fileName))
{
windowTitle = process.MainWindowTitle;
}
}
IntPtr pdfHandle = FindWindow(null, windowTitle);
while (IsWindow(pdfHandle) && userExitedApp == false)
Thread.Sleep(100);
}
Multiple threads could utilize one method one after the other. Perhaps this video will help
https://www.youtube.com/watch?v=XhGXh9Z5GTw&feature=em-upload_owner

detecting that a file is currently being written to

(I know It's a common problem but I couldn't find an exact answer)
I need to write a windows service that monitors a directory, and upon the arrival of a file, opens it, parses the text, does something with it and moves it to another directory afterwards. I used IsFileLocked method mentioned in this post to find out if a file is still been written. My problem is that I don't know how much it takes for another party to complete writing into the file. I could wait a few seconds before opening the file but this is not a perfect solution since I don't know in which rate is the file written to and a few seconds may not suffice.
here's my code:
while (true)
{
var d = new DirectoryInfo(path);
var files = d.GetFiles("*.txt").OrderBy(f => f);
foreach (var file in files)
{
if (!IsFileLocked(file))
{
//process file
}
else
{
//???
}
}
}
I think you might use a FileSystemWatcher (more info about it here: http://msdn.microsoft.com/it-it/library/system.io.filesystemwatcher(v=vs.110).aspx ).
Specificially you could hook to the OnChanged event and after it raises you can check IsFileLocked to verify if it's still being written or not.
This strategy should avoid you to actively wait through polling.

one process waiting for another process's output via the file system

I have a process A that reads in some data produced by some other process B. The data is 'exchanged' via the file system. To ensure that the file exists, process A currently checks for the file's existence like this:
while (!File.Exists(FileLocation))
{
Thread.Sleep(100);
}
This only seems to work 99 percent of the time. The other 1 percent of the time, process A establishes that the file exists but process B has not written everything yet (i.e. some data is missing).
Is there another simpler way to make the above situation more bullet proofed? Thanks.
Is there another simpler way to make the above situation more bullet proofed?
You could use a Mutex for reliable inter-process synchronization. Another possibility is to use a FileSystemWatcher.
After determining that the file exists, you can try opening the file for exclusive access, which will fail if another process still has the file open:
try
{
File.Open("foo",FileMode.Open,FileAccess.Read,FileShare.None);
}
catch(IOException ex)
{
// go back to
}
Given that you say that you can change both processes' code, you can use an EventWaitHandle to communicate between the processes.
In your program that creates the file, in the Main() method you can create an EventWaitHandle and keep it around until the end of the program. You'll need to pass the EventWaitHandle object around in your program so that it is available to the bit of code that creates the file (or provide some method that the file-creating code can call to set the event).
using (EventWaitHandle readySignaller = new EventWaitHandle(false, EventResetMode.ManualReset, "MySignalName"))
{
// Rest of program goes here...
// When your program creates the file, do this:
readySignaller.Set();
}
Then have some code like this in the program that's waiting for the file:
// Returns true if the wait was successful.
// Once this has returned true, it will return false until the file is created again.
public static bool WaitForFileToBeCreated(int timeoutMilliseconds) // Pass Timeout.Infinite to wait infinitely.
{
using (EventWaitHandle readySignaller = new EventWaitHandle(false, EventResetMode.ManualReset, "MySignalName"))
{
bool result = readySignaller.WaitOne(timeoutMilliseconds);
if (result)
{
readySignaller.Reset();
}
return result;
}
}
NOTE: If we successfully wait note that I am resetting the signal and it will remain reset until the other process sets it again. You can handle the logic differently if you need to; this is just an example.
Essentially what we are (logically) doing here is sharing a bool between two processes. You have to be careful about the order in which you set and reset that shared bool.
Try the FileSystemWatcher.
Listens to the file system change notifications and raises events when
a directory, or file in a directory, changes.

C# File.Exists on partially copied file

Lets say for example I had a 20gb file and I decided to copy it to "c:/folder/filename.ext". Obviously this would take some time to complete.
What would the the following return if it was executed whilst the copy was taking place?
File.Exists("c:/folder/filename.ext");
What would the the following return if it was executed whilst the copy was taking place?
Assuming the process you are running your code under has sufficient privileges to read the file it will return True (don't forget that File.Exists returns False if the account doesn't have sufficient privileges to read the file even if the file exists). The File.Exists method doesn't care if the file is currently being written to or read from:
public class Program
{
static void Main()
{
Task.Factory.StartNew(() =>
{
using (var stream = File.OpenWrite("test.dat"))
{
Thread.Sleep(100);
}
});
Thread.Sleep(10);
// prints True
Console.WriteLine(File.Exists("test.dat"));
}
}
I'm not really sure about, but I think it returns true if there is any file (full or partially copied).
If you need the state of you copy process you should check lenght, or use hashing (SHA1).

Categories

Resources