How to copy file programmatically from AFL, was: Problems with the ShellExecute

Hi

I am using the ShellExecute to copy/rename files. I run into a very strange problem: If I use it to rename file A to file B, then I cannot open file B immediately, fOpen() fails! I need to wait a little, like Threadsleep(1000).

Here is the code to test it:

global
Title,
fhRead,
fhWrite,
selected_folder,
FileRead,
FileWrite;


// source_name must contain the path too.
// target_name does not contain the path.
// Handles spaces in filenames and dirnames
// example call:
//     selected_folder = "C:\\some dir\\";
//     rename_file(selected_folder + "my file.txt", "bbb123.txt");
procedure rename_file( source_name, target_name )
{
    local
    x,
    str;

    source_name = "\"" + source_name + "\"";
    target_name = "\"" + target_name + "\"";

    str = "/c rename " + source_name + " " + target_name;
    x = ShellExecute( "cmd", str, "" );

    if( x <= 32 )
        printf( "RENAME-ShellExecute failed, error code = %g \n", x );
}

// source_name must contain the path too.
// target_name must contain the path too.
// Handles spaces in filenames and dirnames
// example call:
//     selected_folder = "C:\\some dir\\";
//     copy_file(selected_folder + "my file.txt", selected_folder + "bbb123.txt");
procedure copy_file( source_name, target_name )
{
    local
    x,
    str;

    source_name = "\"" + source_name + "\"";
    target_name = "\"" + target_name + "\"";

    str = "/c copy " + source_name + " " + target_name;
    x = ShellExecute( "cmd", str, "" );

    if( x <= 32 )
        printf( "COPY-ShellExecute failed, error code = %g \n", x );
}

EnableTextOutput( 0 );
selected_folder = "C:\\test-call-stack\\";
FileRead = "kalimera.afl";
FileWrite = "kalimera.txt" ;
Title = "ATTENTION: make sure that FileWrite does NOT exist, or experiment will fail";

if( ParamTrigger( "Run Fast (with Error!)", "OK" ) )
{
    rename_file( selected_folder + FileRead, FileWrite );
    fhWrite = fopen( selected_folder + FileWrite, "r", true ); // open file for Read

    if( NOT fhWrite )
    {
        printf( "Error opening " + selected_folder + FileWrite + "\n" );
        _TRACE( "Error opening " + selected_folder + FileWrite );
    }
    else
        fclose( fhWrite );
}

if( ParamTrigger( "Run Slow", "OK" ) )
{
    rename_file( selected_folder + FileRead, FileWrite );
    ThreadSleep( 1000 );
    fhWrite = fopen( selected_folder + FileWrite, "r", true ); // open file for Read

    if( NOT fhWrite )
    {
        printf( "Error opening " + selected_folder + FileWrite + "\n" );
        _TRACE( "Error opening " + selected_folder + FileWrite );
    }
    else
        fclose( fhWrite );
}

Please make sure you have the proper directory "C:\test-call-stack\", and a small file inside it: kalimera.afl.

@bobptz,
I never use ShellExcute but JScript is better. You can use AFL Script Host for file manipulation.
https://www.amibroker.com/guide/a_script.html
Here is an example of renaming file.

//Rename temp1.txt to temp.txt
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso.FileExists("C:\\temp.txt")) {
   fso.DeleteFile("C:\\temp.txt");
   WScript.echo( "temp.txt delete" );
} else {
   WScript.echo( "temp.txt not found" );
}
if (fso.FileExists("C:\\temp1.txt")) {
   f=fso.GetFile("C:\\temp1.txt");
   f.name ="temp.txt";
} else {
   WScript.echo( "temp1.txt not found" );
}
fso = null;

Use fso.CopyFile("file1.txt", "file2.txt", 1) for file copy.

Thank you for the code.
I'd rather not do external .JS files for tasks that I could do from inside AFL. If I could do it like this, like @bepe had advised in another post, I might consider:

CreateObject("Shell.Application");

Anyway, I have solved my problem with the delay. I thought to report it for others to know. I would also like a comment from @Tomasz. He may point out to me if I am doing something totally wrong, or maybe he may find some flaw in the windows API that he maybe can fine-tune.

Do NOT call ThreadSleep(). The formulas SHOULD NOT WAIT.

Also using JScript is NOT needed at all. To copy/rename file you can do that from AFL:

fso = CreateObject("Scripting.FileSystemObject");

fso.CopyFile( "file1.txt", "file2.txt" ); // copy
fso.MoveFile( "file2.txt", "file3.txt"); // rename
12 Likes

@Tomasz,
Salute!
The first time I see this kind of code.
Seamless integration of JavaScript in AFL.
Thanks.

Beautiful, flawless, fast.

This is why I asked for @Tomasz 's comment...!