Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CreateFile failing with errorcode 2, while file exists

Tags:

c++

c

winapi

I try to open existing file via CreateFile, but it is always failing with errorcode 2 - like file doesn't exist, but it exists - it's in folder with executable.

hFile = CreateFile( argv[ 1 ], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if ( hFile == INVALID_HANDLE_VALUE )
{
    printf( "\nError: Unable to open file (%d)\n", GetLastError( ) );
    return -1;
}

it fails even if I replace argv[1] with hardcoded filename string. app is running as an admin.

like image 294
encore leet Avatar asked Jul 21 '26 06:07

encore leet


2 Answers

The error code is accurate. The file cannot be found. Possible explanations include:

  • You used the wrong file name.
  • You used a relative path and the process working directory is not what you expect it to be.

If you wish to interpret the file name as being relative to the directory in which the executable resides then do that. Form an absolute path from the directory containing the executable and the specified file name.

There is no reason to expect a process working directory to be the directory in which the executable resides.

like image 114
David Heffernan Avatar answered Jul 23 '26 20:07

David Heffernan


You are attempting to open a file using a relative pathname. Relative pathnames are relative to the current working directory (see GetCurrentDirectory). The current working directory is not necessarily the directory, where the executable image resides. It can be different for a number of reasons, for example:

  • The application was launched through a shortcut that explicitly sets the working directory.
  • The application called SetCurrentDirectory.
  • The application was launched through the command interpreter from a directory other than the executable's directory.

If you want to open a file located relative to the application's executable image, you need to construct a fully qualified pathname, based on the executable's location and the desired filename. The following code retrieves the executable's directory1):

#include <windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include <string>
#include <vector>

std::wstring GetExePath() {
    // Retrieve fully qualified module pathname
    std::vector<wchar_t> buffer( MAX_PATH );
    DWORD cbSize = ::GetModuleFileNameW( nullptr, buffer.data(),
                                         static_cast<DWORD>( buffer.size() ) );
    while ( cbSize == buffer.size() ) {
        buffer.resize( buffer.size() + MAX_PATH );
        cbSize = ::GetModuleFileNameW( nullptr, buffer.data(),
                                       static_cast<DWORD>( buffer.size() ) );
    }
    if ( cbSize == 0 ) {
        throw ::GetLastError();
    }

    // Remove filename from fully qualified pathname
    if ( ::PathRemoveFileSpecW( buffer.data() ) ) {
        ::PathAddBackslashW( buffer.data() );
    }

    // Construct string object from character buffer
    std::wstring str( &buffer[0] );
    return str;
}

This can be used as follows:

int wmain( int argc, const wchar_t* argv[] ) {

    if ( argc <= 1 ) {
        return -1;
    }

    std::wstring pathname = GetExePath();
    pathname += argv[1];
    HANDLE hFile = ::CreateFileW( pathname.c_str(), GENERIC_READ,
                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
                                  NULL, OPEN_EXISTING, 0, NULL );
    if ( hFile == INVALID_HANDLE_VALUE )
    {
        wprintf( L"\nError: Unable to open file (%d)\n", GetLastError() );
        return -1;
    }

    // ...

    ::CloseHandle( hFile );
    return 0;
}


1) Code targeting Windows 8 and later should use PathCchRemoveFileSpec and PathCchAddBackslash instead.
like image 32
IInspectable Avatar answered Jul 23 '26 21:07

IInspectable



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!