Recent

Author Topic: Tprocess not executing dos commands Win7-64  (Read 4954 times)

jack616

  • Sr. Member
  • ****
  • Posts: 268
Tprocess not executing dos commands Win7-64
« on: May 23, 2016, 01:14:53 pm »
Am I doing something silly here?
I've tried both the commandLine and parameter.Add methods to copy a file from
one location to another.
I can make it run using commandLine and robocopy command but dos commands do not seem
to run.
I've tried the copy command itself and also tried running cmd.exe (with its path) and adding the copy
command as a parameter with the proc.add() functions.

In all cases I get and E exception: 2 error.

In short - can I copy a file using the simple dos copy command with Tprocess somehow?

This code should produce my problem (ignore any obvious typos I had to type from another machine):
The lbFilesFound items (fpath variable) are a string line containing drive:path\filename.ext
deDestination.text is drive:path\
I have tried with and without trailing backslashes

Code: [Select]
procedure TFrmTest.SpeedButton1Click(Sender: TObject);   
var
    proc: Tprocess;
    fpath: string;
    i: integer;
    action,param: string;
begin
TRY
     if not (DirpathExists(deDestination.Text) )  then
     begin
      showmessage('Destination path must exist');
      exit;
     end;
     if rbcopy.Checked then
        action := 'COPY'
     else
        action := 'MOVE';
TRY
     proc := TProcess.create(nil);
     proc.CurrentDirectory := extractFileDir(fpath); // probably spurious

     for i := 0 to lbFilesFound.Count -1 do
     begin
        fpath := trim(lbFilesFound.Items.Strings[i]) ;
        if fpath = '' then continue;
        param :=  action + ' ' + fpath + ' ' + deDestination.Text;
        proc.CommandLine := param ;  // This does not work.
{
// this works //  proc.CommandLine:= 'c:\windows\system32\robocopy.exe  ' +  extractfileDir(fpath) + ' ' + deDestination.text + ' ' + extractFilename(fpath) + ' ' + action + ' /LOG+:c:\my.log /V /FP' ;
}
      proc.Execute;
      proc.WaitOnExit;
      if proc.ExitStatus <> 1 then   
        begin
          MessageDlg('Error',
            'Error executing '+ action +#13
            +'Error code: ' + IntToStr(proc.ExitStatus),
            mtError,[mbCancel],0);
        end;//exitStatus

     end;//for i
FINALLY
    proc.free;
END;

EXCEPT
  on E: Exception do
  begin
    showmessage('Program E exception: ' + E.Message);
  end;//on E
END;//except

end;//F
 




Bart

  • Hero Member
  • *****
  • Posts: 5575
    • Bart en Mariska's Webstek
Re: Tprocess not executing dos commands Win7-64
« Reply #1 on: May 23, 2016, 01:29:28 pm »
For internal commands like copy, dir, del etc. you have to invoke cmd.exe /c followed by a space and then the internal command.
Like:
Code: [Select]
cmd.exe /c copy path/to/source /path/to/dest

Mind you that in case of "copy" the command is interactive when the destination already exist, so you might have to add the /y switch to the copy command.

Note that on Win9x systems cmd.exe does not exist (you need to call COMMAND.COM).
The recommende way to get the executable responsible for handling commandline instructions on Windows is querying the COMSPEC environment variable.

Also not that we actually have a CopyFile procedure in Lazarus, so there is no need to call an external application to do it for you.

Bart

jack616

  • Sr. Member
  • ****
  • Posts: 268
Re: Tprocess not executing dos commands Win7-64
« Reply #2 on: May 23, 2016, 03:22:33 pm »
Thats odd - my reply seems to have vanished.
I think my man in middle is active again.

Anyway - Thanks bart - the /c did the trick for the commandLine function.
As this is listed as deprecated I also tried Tprocess.executable with the parameter.Add()
but again this refuses to work for me no matter what I try.
A simple uncluttered example that works somewhere would be nice.

So I'll have to stick with commandline for now -

But I think I may have uncovered a bug - can anyone confirm or explain...

when proc.commandLine := 'c:\windows\system32\cmd.exe /c ' + fpath
is used it works fine and activates the files registry association.

However if the filename happens to have  either '(' or ')'  in it the exit status
errors with 259.
The help list (in
Ide v1.6)I have here doesnt go up that high  but I assume its a parse error somewhere?

With open bracket it generates the error.
With close bracket it both generates the error AND runs the file as if there was no error.
This behaviour occurs with both Tprocess and TprocessUTF8

I also can't get the url format (using '\\?\' prepended on the path) to work - is that implemented
for Tprocess or TprocessUTF8 ?




 

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12303
  • FPC developer.
Re: Tprocess not executing dos commands Win7-64
« Reply #3 on: May 23, 2016, 03:47:00 pm »
I would recommend to use the parameter.add syntax as much as possible.

.commandline is deprecated for a reason. There are simply too many rules for special cases.

Set executable to /path/to/cmd.exe   and parameters

1)  /c

2) the whole copy commandline without quotes surrounding it.


Bart

  • Hero Member
  • *****
  • Posts: 5575
    • Bart en Mariska's Webstek
Re: Tprocess not executing dos commands Win7-64
« Reply #4 on: May 23, 2016, 04:14:16 pm »
This works fine for me:

Code: Pascal  [Select][+][-]
  1.   P := TProcess.Create(nil);
  2.   try
  3.     P.Executable := 'C:\Windows\system32\cmd.exe';
  4.     //P.Executable := '\\?\C:\Windows\System32\cmd.exe';  //this also works for me
  5.     P.Parameters.Add('/c');
  6.     P.Parameters.Add('copy /y (foo) bar');
  7.     P.Execute;
  8.     writeln('ExitCode = ',P.ExitCode);
  9.     writeln('ExitStatus = ',P.ExitStatus);
  10.     OSErr := GetlastOSError;
  11.     writeln('OSError = ',OSErr);
  12.     if OSErr > 0 then writeln(Trim(SysErrorMessage(OsErr)));
  13.   finally
  14.     P.Free;
  15.   end;
  16.  

It outputs
Code: [Select]
C:\Users\Bart\LazarusProjecten\ConsoleProjecten>test
ExitCode = 0
ExitStatus = 259
OSError = 18
Er zijn geen bestanden meer.  //There are no more files
Done

It properly copies the file "(foo)" to "bar".

Odlly when the program terminates 9after it prints "Done" I have to press Return key in the console.

cmd /c may be a little picky about argunents.
type "cmd /?" (without the quotes) in a terminal to see why.

IMO the better solution would still be to do the copy yourself (in Pascal code).

Bart

Thaddy

  • Hero Member
  • *****
  • Posts: 17378
  • Ceterum censeo Trump esse delendam
Re: Tprocess not executing dos commands Win7-64
« Reply #5 on: May 23, 2016, 05:15:58 pm »
Bart is right. Do it from code.
Since you are using Windows, here's a small example with feedback:
Code: Pascal  [Select][+][-]
  1. program testcopyfileex;
  2. {$APPTYPE CONSOLE}
  3. uses
  4.   Windows,
  5.   SysUtils;
  6. // you can connect a progressbar here in a GUI application
  7. function CopyProgressRoutine( TotalFileSize:int64;
  8.                               TotalBytesTransferred:int64;
  9.                               StreamSize:int64;
  10.                               StreamBytesTransferred:Int64;
  11.                               dwStreamNumber:Dword;
  12.                               dwCallbackReason:Dword;
  13.                               hSourceFile:THandle;
  14.                               hDestinationFile:THandle;
  15.                               lpData:Pointer):dword;stdcall;
  16. begin
  17.   writeln(TotalbytesTransferred * 100 div TotalFileSize,'% ',StreamBytesTransferred,' bytes');
  18.   result := 0;
  19. end;
  20.  
  21. var
  22.   Old,New:AnsiString;
  23.   Cancel:Boolean;
  24. begin
  25.   Old := 'C:\Users\Thaddy\OneDrive\Openbaar\fpctrunk-r33121.zip';// maybe paramstr[1]
  26.   New := 'd:\fpctrunk-r33121.zip';// maybe paramstr[2]
  27.   Cancel := false;
  28.   if CopyFileEx(@Old[1],@New[1],@CopyProgressRoutine,nil,@Cancel,0) then
  29.     writeln('Success')
  30.   else
  31.     writeln(SysErrorMessage(GetLastError));
  32.   readln;
  33. end.
« Last Edit: May 23, 2016, 05:23:44 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

jack616

  • Sr. Member
  • ****
  • Posts: 268
Re: Tprocess not executing dos commands Win7-64
« Reply #6 on: May 23, 2016, 05:57:01 pm »
Thanks guys - yes I agree things get deprecated for a reason which is why I kept trying.
The example you gave shows me what I had missunderstood about the parameters I think.

Thaddy - The message I posted explaining I'm using the copy command just as an example went missing
- sorry I cant explain that. The point was I'm doing a number of things with this
so a simple fileCopy doesn't do it for me - I need to use the Tprocess.

bart : does   P.Parameters.Add('copy /y \\?\(foo) \\?\bar'); work?
Maybe extra quoting is needed - I've not tried that yet.

The brackets in filenames is a troubling issue - this occurs when trying to call the file association
via cmd.exe  -

Assuming image associations are set
try something like    proc.commandLine := 'cmd.exe /c ' + 'c:\nam(e.jpg'
Maybe thats one reason commandLine was deprecated - I dont know as I havn't
been able to use the other method as yet.

Marcov thanks - I'll give it a go - no quotes sounds counter intuitive if I even understand correctly.

Bart

  • Hero Member
  • *****
  • Posts: 5575
    • Bart en Mariska's Webstek
Re: Tprocess not executing dos commands Win7-64
« Reply #7 on: May 23, 2016, 06:25:53 pm »
This works OK:
Code: Pascal  [Select][+][-]
  1.     P.Parameters.Add('copy /y \\?\C:\Users\Bart\LazarusProjecten\ConsoleProjecten\(foo) \\?\C:\Users\Bart\LazarusProjecten\ConsoleProjecten\bar');
  2.  

Bart

Bart

  • Hero Member
  • *****
  • Posts: 5575
    • Bart en Mariska's Webstek
Re: Tprocess not executing dos commands Win7-64
« Reply #8 on: May 23, 2016, 06:28:47 pm »
If you know how to do it on the commandline, you can also create a batchfile with the appropriate commands and then execute the batchfile.

Alternatively you an explain what you want to achieve, and maybe we can give clues as to how to do that entirely in code?

Bart

jack616

  • Sr. Member
  • ****
  • Posts: 268
Re: Tprocess not executing dos commands Win7-64
« Reply #9 on: May 23, 2016, 07:18:21 pm »
Please see line one of post 1  :'(

I'm looping the process ... I was adding but not clearing the parameters first on each loop! DUH!
proc.parameters.clear;

This seems to have solved the issues.
Thanks to all for the efforts. And I've learned quite a bit so worthwhile I guess.

Still concerned about the brackets in filename issues though.



 

TinyPortal © 2005-2018