I'm trying to read file from the directory the exe file is located. The data.txt file is in VS Project directory and when I specify the full path everything works fine.
char curDirectory[MAX_PATH];
GetCurrentDirectory(MAX_PATH, curDirectory);
char filePath[MAX_PATH];
char *name = "\\data.txt";
memcpy(filePath, curDirectory, sizeof(curDirectory));
memcpy(filePath + strlen(curDirectory), name, strlen(name));
HANDLE hFile = CreateFile(filePath, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
You don't null terminate the string. Do so by passing strlen(name) + 1 in the second call to memcpy.
Some other observations:
When CreateFile fails, you should call GetLastError to obtain an error code.
Use strcpy and strcat rather than memcpy when working with strings.
That said, your code asks to overrun the buffer. If this really is C++, use std::string and have that class manage buffers.
There is no real reason to believe that the executable file is located in the current working directory.
Related
I am trying to make an image viewer, and everything works when I hard code the path of the file, but when I try to get the path so I can open files with it, it doesn't work, nothing happens.
When debugging, I found out that CreateFileA returns INVALID_HANDLE_VALUE.
This leads me to believe that the error should be in these 2 lines of code.
LPSTR FileA = GetCommandLine();
HANDLE FileHandle = CreateFileA(FileA, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
When CreateFileA() returns INVALID_HANDLE_VALUE on failure, use GetLastError() to find out WHY it failed. But in this case, GetCommandLine() is likely not returning the path you are expecting.
Assuming that is actually calling the Win32 GetCommandLineA() function, and not some other function in your program, then that function returns the command line that was used to launch the calling process, ie "C:\<path>\myapp.exe <parameters>". If there are no <parameters> present, then you would be trying to open your own program's EXE, not an image file. And if there are <parameters> present, then you would be passing an invalid file path to CreateFileA().
You need to parse the command line to extract just the file path you actually want, THEN you can try to open the file at that path. Have a look at Parsing C Command-Line Arguments and Parsing C++ Command-Line Arguments . Consider using CommandLineToArgvW() to make that easier.
I am having an issue with my application as while reading a file that consists of Unicode characters too. As I am using the CreateFileA method to get the data but it doesn't get the Unicode characters properly for which I am facing a lot of issues. Also, I don't know the difference between CreateFileA and CreateFileW.
I'm sorry I couldn't able to share my code. I will share my that portion of code with you.
HANDLE systemFileHandle = INVALID_HANDLE_VALUE;
systemFileHandle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
char* inBuffer=new char[totalFileSize+2];
memset(inBuffer, 0, totalFileSize+2);
ReadFile(systemFileHandle, inBuffer, totalFileSize, &bytesRead, nullptr);
And, I am getting the results on inBuffer array be like : Fernw�rmestationSW Au�en.
Can't I get it the original way they are?
So can you please help me out with this. It can be very helpful.
CreateFileA takes an ANSI-based file name, while CreateFileW takes a Unicode-based file name. There's nothing to say about the content of the file, both will return a HANDLE to the file where you can then read/write Unicode content as needed.
In this code, Im writing some text to a memory mapped text file. Data is written to the file successfully, but when i open it with notepad, after the written data, "NULL" is repeatedly written upto the mapped memory limit which is greater than the text i have written.
What could be the possible reason?
pLogMsg = (char*)calloc(1024,sizeof(char));
printf("[INFO] entering logger writeback thread\n");
log_file = CreateFile (TEXT("one.txt"), // Open one.txt.
GENERIC_READ | GENERIC_WRITE, // Open for reading and writing
FILE_SHARE_WRITE, // file share
NULL, // No security
OPEN_ALWAYS, // Open or create
FILE_ATTRIBUTE_NORMAL, // Normal file
NULL); // No template file
if (log_file == INVALID_HANDLE_VALUE)
{
printf("%d [ERR] cant open file GLE %d\n",GetCurrentThreadId(),GetLastError());
return -1;
}
hMapping = CreateFileMapping( log_file, 0, PAGE_READWRITE, 0,4096 ,0 );
if (hMapping == INVALID_HANDLE_VALUE)
{
printf("%d [ERR] cant create file mapping %d\n",GetCurrentThreadId(),GetLastError());
return -1;
}
pFileData = (CHAR*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0,0, 0 );
if (pFileData == NULL)
{
printf("%d [ERR] cant mapview of file %d\n",GetCurrentThreadId(),GetLastError());
return -1;
}
pLogMsg = LogPrint();//returns a null terminated string
memcpy(pFileData,pLogMsg,strlen(pLogMsg));
pFileData += strlen(pLogMsg);
free(pLogMsg);
first of all CreateFileMapping and MapViewOfFile this is bad solution for log file. you need create/open file with FILE_APPEND_DATA access instead GENERIC_READ | GENERIC_WRITE - so call must look like:
HANDLE log_file = CreateFileW(L"one.txt",
FILE_APPEND_DATA,
FILE_SHARE_WRITE|FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
in this case you open file with FILE_APPEND_DATA and SYNCHRONIZE (because no FILE_FLAG_OVERLAPPED):
If the caller sets only the FILE_APPEND_DATA and SYNCHRONIZE flags, it
can write only to the end of the file, and any offset information
about write operations to the file is ignored. The file will
automatically be extended as necessary for this type of operation.
after this you need log via WriteFile - it will be automatically append to the end of file. this is what exactly need for log file.
however, if want use CreateFileMapping and MapViewOfFile - at first CreateFileMapping return 0 on error, so check
if (hMapping == INVALID_HANDLE_VALUE) is wrong
if you want change file size - you need use for this SetFileInformationByHandle with FileEndOfFileInfo (vista+)or NtSetInformationFile with FileEndOfFileInformation (working everywhere, how not hard understand SetFileInformationByHandle is only very thin shell over NtSetInformationFile or ZwSetInformationFile (in user mode this is the same function)). use SetFilePointer followed by SetEndOfFile also possible but bad and not effective choice - you will be have 2 calls in src code instead on single. in binary - you will even more worse situation: first you set file position, that SetEndOfFile read this file position and finally call NtSetInformationFile with this position. so 3 calls instead one. and assume that nobody change file position (on this handle) between SetFilePointer and SetEndOfFile calls
but need clear understand that call SetFileInformationByHandle with FileEndOfFileInfo you can only after you unmap view and close section. otherwise you got error ERROR_USER_MAPPED_FILE (STATUS_USER_MAPPED_FILE )
If CreateFileMapping is called to create a file mapping object for
hFile, UnmapViewOfFile must be called first to unmap all views and
call CloseHandle to close the file mapping object before you can
call SetEndOfFile.
There is no 'end of file' marker within the file. You need to set the file length, so the OS marks it correctly.
See MSDN documentation for SetEndOfFile
Sets the physical file size for the specified file to the current position of the file pointer.
You cannot set the end-of-file marker through a file mapping. The end-of-file marker does not physically exist in a file. It is a flag raised by the OS when reading past the end of a file.
To set the size of a file you will have to call SetFilePointer followed by SetEndOfFile on the file object used to create the file mapping.
I am debugging a custom exe during the compiling of my code using the msbuild exec task.
It runs the following code:
HANDLE hFile = CreateFileA(szFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
Fatal(szFile, 1, "unable to open file (%x)", GetLastError());
szFile is the dll/exe that was compiled by msbuild, which is passed to program as an argument.
I am seeing the following error sometimes:
unable to open file (20)
After rebuilding the error doesn't happen again. According the the windows codes, error code 20 is:
ERROR_BAD_UNIT20 (0x14)
The system cannot find the device specified.
I'm not sure what this mean though. It doesn't seem to be that the file in question doesn't exist, because it does. If it didn't the error code would be "2", I've tried. Do you know what can cause this error? Thanks.
Couple of things:
const char *szFile = nullptr;
...
szFile = argv[i]; // it loops over the arguments, parses them and finds the right argment for the file.
....
SetFileAttributes(szFile, FILE_ATTRIBUTE_NORMAL);
HANDLE hFile = CreateFileA(szFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
Fatal(szFile, 1, "unable to open file (%x)", GetLastError());
Fatal() just does a printf of the file name and message.
You're printing the error code in hexadecimal (%x) rather than in decimal.
Error code 0x20 (32 decimal) is ERROR_SHARING_VIOLATION ("The process cannot access the file because it is being used by another process.") So, yes, your guess about another process having the file open was correct.
In these circumstances, I suspect a race condition, possibly affected by virus scanning. Consider having your code detect this particular error and retry after a short wait.
so I am new to the whole c++ windows API. I'm creating a simple dialogbox in which the user types in a directory into a textbox for a time file which has already been created. the program will then read the file and display the time in another edit control. Im having a few problems making the directory entered the parameter for CreateFile(). If I hard code the directory in, the program will work correctly. But I cant figure out how to take the textbox data and plug it into the CreateFile() function. if this doesn't make sense i can try an explain differently. Ive searched an can't seem to find anything.
Thanks
for example:
if the user types c:\test\time.txt into the text box I want "c:\test\time.txt" to be the put into CreateFile();
CHAR temp[20] = "";
HANDLE hFile;
GetDlgItemText(hDlg, IDC_TEXTIN, temp, 20);//IDC_TEXTIN is name of edit control
//open file
hFile = CreateFile(
temp,
GENERIC_READ | GENERIC_WRITE,
0, // no sharing
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL // no template
);