13

I am in need of an example, that can let me pass a parameter

e.g. executing delete.exe /killme.txt

So it will use the "MoveFile" to delete killme.txt after reboot.

Although please not the MS precompiled version, as it has an annoying disclaimer, every time its run on a different computer.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Jay
  • 189
  • 1
  • 2
  • 7
  • What "MoveFile" function are we talking about here? – Jeff Mercado May 20 '11 at 21:47
  • @Jeff Mercado There is a MS application called "movefile.exe" that allows you to mark a file for deletion on reboot – Jay May 20 '11 at 21:48
  • @Jeff: I believe he is referring to [MOVEFILE_DELAY_UNTIL_REBOOT](http://msdn.microsoft.com/en-us/library/aa365240(v=vs.85).aspx) – user7116 May 20 '11 at 21:49
  • @sixlettervariables Thats the one – Jay May 20 '11 at 21:49
  • See this [question](http://stackoverflow.com/questions/5490658/how-can-i-delay-file-deletion-until-next-reboot-from-my-program/5490755#5490755). You're looking for MoveFileEx. – Ken White May 20 '11 at 21:52
  • 2
    I had to ask because although there's an API function, you made it sound like you're talking about a program. As @six points out, the API can do this for you. – Jeff Mercado May 20 '11 at 21:58

2 Answers2

25

You'll need the P/Invoke declarations for MoveFileEx:

[Flags]
internal enum MoveFileFlags
{
    None = 0,
    ReplaceExisting = 1,
    CopyAllowed = 2,
    DelayUntilReboot = 4,
    WriteThrough = 8,
    CreateHardlink = 16,
    FailIfNotTrackable = 32,
}

internal static class NativeMethods
{
    [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
    public static extern bool MoveFileEx(
        string lpExistingFileName,
        string lpNewFileName, 
        MoveFileFlags dwFlags);
}

And some example code:

if (!NativeMethods.MoveFileEx("a.txt", null, MoveFileFlags.DelayUntilReboot))
{
    Console.Error.WriteLine("Unable to schedule 'a.txt' for deletion");
}
user7116
  • 63,008
  • 17
  • 141
  • 172
  • 1
    Meta comment: `MoveFileEx` with `DelayUntilReboot` will only fail on a *registry problem* rather than a deletion problem. – user7116 May 20 '11 at 21:58
  • 1
    +1. Nice. I didn't have a C# example handy, but had the reference to the API call directly (see my comment to the original question). – Ken White May 20 '11 at 22:02
  • Elegant. I did not know that you could delay a file deletion after reboot with existing Windows API and not using some sort of Task Scheduler. +1 – David Anderson May 20 '11 at 22:27
  • 5
    +1. Seems to require administrator privileges. It will fail without throwing exception so you need to look at the value returned by GetLastError(). – Salman A Feb 22 '12 at 07:05
  • How can I do if I want to move more then 1 file on reboot? Is this possible or exists another nice workaround for multiple files? – Patrick Jan 09 '14 at 13:39
6

Because you want to perform this after reboot as a requirement, you could use the Windows Task Scheduler API. You can invoke this in C# by adding a reference to the COM library TaskScheduler 1.1 Type Library. Below is a full code example on running Notepad.exe at logon.

Also, here is another resource: http://bartdesmet.net/blogs/bart/archive/2008/02/23/calling-the-task-scheduler-in-windows-vista-and-windows-server-2008-from-managed-code.aspx

You could call the system command DEL from Windows Command line, potentially with this code.

namespace TaskSchedulerExample {
    using System;
    using TaskScheduler;

    class Program {
        static void Main(string[] args) {
            var scheduler = new TaskSchedulerClass();
            scheduler.Connect(null, null, null, null);

            ITaskDefinition task = scheduler.NewTask(0);
            task.RegistrationInfo.Author = "DCOM Productions";
            task.RegistrationInfo.Description = "Demo";

            ILogonTrigger trigger = (ILogonTrigger)task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_LOGON);
            trigger.Id = "Logon Demo";

            IExecAction action = (IExecAction)task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
            action.Id = "Delete";
            action.Path = "c:\\delete.exe";          // Or similar path
            action.WorkingDirectory = "c:\\";        // Working path
            action.Arguments = "c:\\killme.txt";     // Path to your file

            ITaskFolder root = scheduler.GetFolder("\\");
            IRegisteredTask regTask = root.RegisterTaskDefinition("Demo", task, (int)_TASK_CREATION.TASK_CREATE_OR_UPDATE, null, null, _TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");

            //Force run task
            //IRunningTask runTask = regTask.Run(null);
        }
    }
}

This gives you some flexibility. You could run your own delete.exe, or you could potentially invoke the Windows Command Line to execute the DEL command.

David Anderson
  • 13,558
  • 5
  • 50
  • 76
  • `Copyright (c) DCOM Productions. All rights reserved.`? That statement creates legal problems with using this code. – Nate Jun 27 '13 at 19:24
  • 1
    I own the company, so not really, but I should have not posted the copyright header. Force of habit. Enjoy the code :) – David Anderson Jun 27 '13 at 19:43