How to Schedule a task programmatically - delphi

How can I schedule a task using delphi 7 like Google updater?
I'm not using the registry because it gets detected by Kaspersky antivirus as a false alarm.
Anything I add in the registry as a start-up item gets detected as a trojan so I decided to use task schedule

The following piece of code shows how to delete and create the task which will run the application at system startup with system privileges. It uses the following command line:
However the Task Scheduler since Windows Vista supports force creation of tasks, I wouldn't use it for backward compatibility with Windows XP, where this flag doesn't exist.
So the example below tries to delete the task (if already exists) and then create the new one.
It executes these commands:
schtasks /delete /f /tn "myjob"
schtasks /create /tn "myjob" /tr "C:\Application.exe" /sc ONSTART /ru "System"
/delete - delete the task
/f - suppress the confirmation
/create - create task parameter
/tn - unique name of the task
/tr - file name of an executable file
/sc - schedule type, ONSTART - run at startup
/ru - run task under permissions of the specified user
And here is the code:
uses
ShellAPI;
procedure ScheduleRunAtStartup(const ATaskName: string; const AFileName: string;
const AUserAccount: string);
begin
ShellExecute(0, nil, 'schtasks', PChar('/delete /f /tn "' + ATaskName + '"'),
nil, SW_HIDE);
ShellExecute(0, nil, 'schtasks', PChar('/create /tn "' + ATaskName + '" ' +
'/tr "' + AFileName + '" /sc ONSTART /ru "' + AUserAccount + '"'),
nil, SW_HIDE);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ScheduleRunAtStartup('myjob', 'C:\Application.exe', 'System');
end;

Figured Out the problem here it works fine
Tested on windows 7 Pro if any one can test for me on XP PRO would b appreciated
procedure ScheduleRunAtStartup(const ATaskName: string; const AFileName: string;
const GetPCName: string ; Const GetPCUser: String);
begin
ShellExecute(0, nil, 'schtasks', PChar('/delete /f /tn "' + ATaskName + '"'),
nil, SW_HIDE);
ShellExecute(0, nil, 'schtasks', PChar('/create /tn "' + ATaskName + '" ' + '/tr "' + QuotedStr(AFileName) + '" /sc ONLOGON /ru "' + GetPCName+'\'+GetPCUser + '"'), nil, SW_HIDE)
end;

Related

How can cmd.exe be automatically closed after execution?

I run cmd.exe to move a file with Administrator rights:
ThisParams := '/K move ' + '"' + ThisSourceFile + '"' + ' ' + '"' + ATargetFile + '"';
Winapi.ShellAPI.ShellExecute(0, 'runas', 'cmd.exe', PChar(ThisParams), '', Winapi.Windows.SW_HIDE);
However, the cmd.exe process (although invisible) after execution remains active and in memory and stays visible in Task Manager.
How can cmd.exe, in this case, be automatically closed after execution?
As documented /k makes the command interpreter to continue running after executing the passed command. You should instead use
/c   Carries out the command specified by String and then stops.

CreateProcess : escape spaces in the application path

We need to execute ffmpeg in a command window in my delphi application.
We found the solution to protect the path with the function "ExtractShortPathName".
But on some computers we can't get the 8.3 path (HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation is 2) and we want to find another way to escape the spaces.
Here is the code :
sParameters := '"C:\Users\[...]\input.wav" -r 12.03 -f image2 -i "C:\Users\[...]\delphilm%d.png" -vf "scale=1024:704" -ab 96k -r 24 -b 2000k -pass 1 -vcodec libx264 -fpre "C:\[...]\libx264-normal.ffpreset" "C:\Users\[...]\export.mp4"';
sCommand := 'C:\Program Files\My application\utils\bin\ffmpeg.exe';
Handle := CreateProcess(nil, PChar('cmd.exe /C '+ProtectPath(sCommand)+' '+sParameters),nil, nil, True, 0, nil, nil, SI, PI);
With the ProtectPath function :
function ProtectPath(sCommand:Widestring):Widestring;
begin
Result := sCommand;
// get the 8.3 path
Result := ExtractShortPathName(sCommand);
// if 8.3 path is not accessible
if(Pos(' ', Result)>0)then begin
//Result := '"'+sCommand+'"'; --> do not work
//Result := StrReplace(sCommand, ' ','" "'); --> do not work
//Result := StrReplace(sCommand, ' ','^ '); --> do not work
//Result := StrReplace(sCommand, ' ','\ '); --> do not work
//Result := StrReplace(sCommand, ' ','\\ '); --> do not work
//Result := StrReplace(sCommand, ' ','/ '); --> do not work
//Result := StrReplace(sCommand, ' ','// '); --> do not work
end;
end;
Any ideas ?
You do not need to retrieve the 8.3 filename. All you have to do is wrap a long path with a single pair of quotation marks if it contains any space characters in it (like you are already doing with some of your FFMPEG parameters). Then, get rid of cmd.exe altogether and just call ffmpeg.exe directly instead.
sCommand := '"C:\Program Files\My application\utils\bin\ffmpeg.exe"';
sParameters := '"C:\Users\[...]\input.wav" -r 12.03 -f image2 -i "C:\Users\[...]\delphilm%d.png" -vf "scale=1024:704" -ab 96k -r 24 -b 2000k -pass 1 -vcodec libx264 -fpre "C:\[...]\libx264-normal.ffpreset" "C:\Users\[...]\export.mp4"';
Handle := CreateProcess(nil, PChar(sCommand + ' ' + sParameters), nil, nil, True, 0, nil, nil, SI, PI);
If you want to do the quoting dynamically, use (Ansi)QuotedStr() for that, eg:
function ProtectParam(sParam: String): String;
begin
if LastDelimiter(' "', sParam) <> 0 then
Result := QuotedStr(sParam)
else
Result := sParam;
end;
FFMPEG := 'C:\Program Files\My application\utils\bin\ffmpeg.exe';
InputFile := 'C:\Users\[...]\input.wav';
PngFile := 'C:\Users\[...]\delphilm%d.png';
PresetFile := 'C:\[...]\libx264-normal.ffpreset';
ExportFile := 'C:\Users\[...]\export.mp4';
sCommand := ProtectParam(FFMPEG) + ' ' + ProtectParam(InputFile) + ' -r 12.03 -f image2 -i ' + ProtectParam(PngFile) + ' -vf "scale=1024:704" -ab 96k -r 24 -b 2000k -pass 1 -vcodec libx264 -fpre ' + ProtectParam(PresetFile) + ' ' + ProtectParam(ExportFile);
Handle := CreateProcess(nil, PChar(sCommand), nil, nil, True, 0, nil, nil, SI, PI);
I don't see any real reason to use cmd.exe here. It's just adding an extra layer of complexity that burns you. You are asking cmd.exe to call CreateProcess to start ffmpeg, so why not do it directly?
That said, a cheap and cheerful way to side-step the problem is to make use of the working directory. Pass 'C:\Program Files\My application\utils\bin' for the working directory of the new process, and then PChar('cmd.exe /C ffmpeg.exe '+sParameters) is all you need.

How to use Delphi to execute a .bat file properly

I am running a .bat file from delphi(2010).
procedure TForm1.Button2Click(Sender: TObject);
var sCmd: String;
Begin
sCmd := Pwidechar('b4a_c2dm.bat' +' ' +'send ' + Trim(Edit1.Text)+' ' + Trim(edit2.Text ));
ShellExecute(0, 'open', 'b4a_c2dm.bat', PChar(sCmd), nil, SW_SHOWMAXIMIZED);
end;
This opens the cmd.exe and passes the correct string in the cmd.exe , BUT
Some how the line in the .bat file (java -cp b4a_c2dm.jar anywheresoftware.b4a.c2dm.C2DM %*) is showing up in the cmd.exe window and not letting the .bat file do its job.
Can someone help me with this.
In order to execute a batch file, the program to be called is 'cmd' and its parameter should be the name of the batch file.
Regarding your program,
ShellExecute (application.handle, 'open', 'cmd', PChar(sCmd), nil, SW_MAXIMIZE)

Send Parameter To CMD

How can i send parameters to CMD? for example send a path and start it from that path? How can i execute CMD commands?
Thanks
To start cmd.exe and immediately execute a command, use the /K flag:
procedure TForm1.FormCreate(Sender: TObject);
begin
ShellExecute(Handle, nil, 'cmd.exe', '/K cd C:\WINDOWS', nil, SW_SHOWNORMAL);
end;
To run a command in cmd.exe and then immediately close the console window, use the /C flag:
procedure TForm1.FormCreate(Sender: TObject);
begin
ShellExecute(Handle, nil, 'cmd.exe', '/C del myfile.txt', nil, SW_SHOWNORMAL);
end;
You can also use the Process class - see an example below
AProcess := TProcess.Create(nil); // Create process
AProcess.Executable := 'cmd'; // Executable to run
AProcess.Parameters.Add('/T:B0'); // Set background colour
AProcess.Parameters.Add('/K'); // Keep open
AProcess.Parameters.Add('title'); // A title for cmd
AProcess.Parameters.Add('My Console'); // Title
AProcess.Parameters.Add('&&'); // Start a new command line
AProcess.Parameters.Add('cd'); // Change directory
AProcess.Parameters.Add('D:\X\'); // Path to Folder
{Set environment variable}
AProcess.Parameters.Add('&&'); // Start a new command line
AProcess.Parameters.Add('HOME='+MYSQL_DIR); // Set env example
AProcess.Parameters.Add('&&'); // Start a new command line
AProcess.Parameters.Add('mysql.exe'); // run mysql.exe
AProcess.Parameters.Add('--host=' + VAR_HOST); // Parameter server
AProcess.Parameters.Add('--port=' + VAR_PORT); // Parameter mysql server port
AProcess.Execute; // execute detatched process command window remains visible
AProcess.Free; // free memory

How to run command line from Delphi?

How can I run this command from my Delphi application?
C:\myapppath\appfolder>appname.exe /stext save.txt
I tried the following code:
ShellExecute(0, nil, 'cmd.exe', 'cd C:\myapppath\appfolder', nil, SW_Hide);
ShellExecute(0, nil, 'cmd.exe', 'appname.exe /stext save.txt', nil, SW_Hide);
But it didn't work. Can anyone provide a solution?
To run a CMD command, you need to use the /C flag of cmd.exe:
ShellExecute(0, nil, 'cmd.exe', '/C cd C:\myapppath\appfolder', nil, SW_HIDE);
ShellExecute(0, nil, 'cmd.exe', '/C appname.exe /stext save.txt', nil, SW_HIDE);
However, this will create two different sessions, so it will not work. But you can use ShellExecute to run appname.exe directly, like so:
ShellExecute(0, nil, 'appname.exe', '/stext save.txt', nil, SW_HIDE);
But you need to specify the filenames properly.
I would do
var
path: string;
begin
path := ExtractFilePath(Application.ExeName);
ShellExecute(0, nil, PChar(Application.ExeName), PChar('/stext "' + path + 'save.txt"'), nil, SW_HIDE);
end;
in case appname.exe is the current application. Otherwise, replace Application.ExeName with the full path of appname.exe.

Resources