0

I am using MoveFileEx() API to move an existing file to a new file. I'm executing below program multiple times via a script.

Below program creates a unique file on every execution, and moves it to some file, say FinalCAFile.txt. But, for some process execution, I'm getting an "Access is denied" error.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <fstream>
#include <process.h>

using namespace std;

#define BUFSIZE 1024

void PrintError(LPCTSTR errDesc,string process_id);


int main(int argc, TCHAR* argv[])
{
    BOOL fSuccess = FALSE;

    //Get process id to create unique file
    std::string process_id = std::to_string(_getpid());

    std::string tempCaFile = "C://Users//Administrator//source//repos//MyProgram//Debug//tempCAFile" + process_id + ".txt";;
    std::string finalCaFile = "C://Users//Administrator//source//repos//MyProgram//Debug//FinalCAFile.txt";

    //Create unique temp CA file 
    std::ofstream file(tempCaFile);
    std::string my_string = "Hello from process " + process_id;
    file << my_string;

    std::wstring sourceTempCAFile = std::wstring(tempCaFile.begin(), tempCaFile.end());
    std::wstring finalCAFile = std::wstring(finalCaFile.begin(), finalCaFile.end());

    file.close();

    //move temporary created file to FinalCAFile.txt
    fSuccess = MoveFileEx(sourceTempCAFile.c_str(),
                finalCAFile.c_str(),
                MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
    if (!fSuccess)
    {
        cout<<endl<<"\nMoveFileEx failed for"<<process_id;
        file.close();
        PrintError(TEXT("MoveFileEx failed"),process_id);
        return (9);
    }
    else
    {
        cout << endl<<"\nMoveFileEx Success for " << process_id;
        std::string passedFileName = "C://Users//Administrator//source//repos//MyProgram//Debug//PassedFile" + process_id + ".txt";
        std::ofstream passedFile(passedFileName);
        std::string my_string = "Passed for process id: " + process_id;
        passedFile << my_string;
        passedFile.close();
    }

    file.close();
    return (0);
}

//  ErrorMessage support function.
//  Retrieves the system error message for the GetLastError() code.
//  Note: caller must use LocalFree() on the returned LPCTSTR buffer.
LPCTSTR ErrorMessage(DWORD error, string process_id)
{
    LPVOID lpMsgBuf;
    //error = 5;
    printf("\nDWORD=%d", (unsigned int)error);
    std::string failedFileName = "C://Users//Administrator//source//repos//MyProgram//Debug//FailedFile" + process_id + ".txt";
    std::ofstream failedFile(failedFileName);
    
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
        | FORMAT_MESSAGE_FROM_SYSTEM
        | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        error,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0,
        NULL);

    std::string my_string = "Failed for process id: " + process_id + " due to " + std::to_string((unsigned int)error) ;
    failedFile << my_string;


    return((LPCTSTR)lpMsgBuf);
}

//  PrintError support function.
//  Simple wrapper function for error output.
void PrintError(LPCTSTR errDesc, string process_id)
{
    LPCTSTR errMsg = ErrorMessage(GetLastError(), process_id);
    _tprintf(TEXT("\n** ERROR ** %s: %s\n"), errDesc, errMsg);
    Sleep(10000);
    LocalFree((LPVOID)errMsg);
}

MyScript.bat

FOR /L %%i IN (1,1,50) DO (
   start  C:\Users\Administrator\source\repos\ConsoleApplication4\Debug\MyProgram.exe
)

As per my understanding, we get the "Access is denied" error if there is a write permission issue.

But here, in my case, I'm executing the same program multiple times, so I don't know how a permission issue comes into the picture.

So, there seems to be some synchronization issue.

Also, there may be the possibility that MoveFileEx() doesn't support a proper locking mechanism internally. I doubt if there is a synchronization issue with MoveFileEx(), then others might also get this issue.

Any suggestion to avoid this issue?

This above script starts executing MyProgram.exe 50 times, and on some executions few processes are giving the "Access is denied" error.

The result is inconsistent, I don't get the error on every script run, but after 2-3 runs I'm able to get the error.

  • 2
    `std::wstring(tempCaFile.begin(), tempCaFile.end())` - That's not how you convert a narrow character string to a wide character string. Use [`MultiByteToWideChar`](https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar) instead, or one of the CRT interfaces. – IInspectable May 31 '22 at 17:28
  • 3
    Or, you can use `MoveFileExA()` instead, then you don't have to convert `std::string` to `std::wstring` at all. Or, just start with `std::wstring` to begin with and don't use `std::string`. But in any case, your file path literals should be using either `/` or ```\\``` instead of `//`. – Remy Lebeau May 31 '22 at 19:59
  • Yes we can use that , but I don't think issue is related to the suggested change . – ganesh nimbolkar Jun 01 '22 at 01:49
  • Probably antivirus software. Try running procmon to see if anything else is accessing your files. – Luke Jun 01 '22 at 07:10
  • You could try running your application with administrative privileges / elevated process. And If you're running antivirus on the machine, it could be locking the new folder while it verifies it/adds it to its clean cache. – Jeaninez - MSFT Jun 01 '22 at 07:38

0 Answers0