I have a problem about managing an exception. In my code I put hIn = INVALID_HANDLE_VALUE to test the exception, and "null" is a non existing file. My piece of code is
__try
{
hIn = CreateFile (_T("null"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
hIn = INVALID_HANDLE_VALUE;
ReadFile (hIn, buffer, BUF_SIZE*sizeof(DWORD), &nIn, NULL);
}
__except(GetExceptionCode() == EXCEPTION_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
_tprintf (_T("-> Error OPENING FILE <-\n"));
return -1;
}
I don't understand why it doesn't catch the exception. What is the problem?
Thank you in advance
The __except block is never entered because ReadFile does not throw exceptions.
Remember that the Windows API is agnostic of programming language and needs to present an interface that can be consumed by any programming language. And not all languages have support for exceptions, and even those that do use different mechanisms. So for an API like the Windows API, throwing exceptions is simply not an option.
Both of the API calls in your question indicate errors by their return values. You need to check these return values and act accordingly. Not all functions report errors in the same way so you need to pay close attention to the documentation for each API function that you call.
The C-function (Win32 API) ReadFile() doesn't normally throw an exception. Instead check return value of ReadFile and if FALSE, call GetLastError() to get the error code.
Have you btw enabled SEH ? See compiler switch /EHsc
see
As others have stated, your __except does not catch an exception because there is no exception being raised in the first place. You need to check return values and error codes instead:
hIn = CreateFile (_T("null"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hIn == INVALID_HANDLE_VALUE)
{
_tprintf (_T("-> Error %u OPENING FILE <-\n"), GetLastError());
return -1;
}
...
ReadFile (hIn, buffer, BUF_SIZE*sizeof(DWORD), &nIn, NULL);
...
CloseHandle(hIn);
Related
I want to modify a single attribute on a file (e.g the read-only attribute). In order to do that, it looks like I have to query the current file attributes with either GetFileAttributes or GetFileInformationByHandle, then set the new attributes with either SetFileAttributes or SetFileInformationByHandle: https://learn.microsoft.com/en-us/windows/win32/fileio/retrieving-and-changing-file-attributes
However that is inherently racy, as the file attributes may change between the query and the update. Is there a method to update file attributes atomically? I would expect there to be an API like ModifyFileAttributes(DWORD addAttributes, DWORD rmAttributes) which would do its best to work atomically. Transactional NTFS is not an option for me because a) it's deprecated b) only works on NTFS.
Thanks!
As mentioned in the comment, FILE_SHARE_READ is a trade-off. The following code is adapted from SetFileInformationByHandle function. SetFileInformationByHandle for hFile2 is ERROR_ACCESS_DENIED.
#include <Windows.h>
#include <Tchar.h>
int main()
{
//...
HANDLE hFile1 = CreateFile(TEXT("tempfile"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
0,
NULL);
HANDLE hFile2 = CreateFile(TEXT("tempfile"),
GENERIC_READ,
FILE_SHARE_READ| FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
0,
NULL);
if (hFile1 != INVALID_HANDLE_VALUE && hFile2 != INVALID_HANDLE_VALUE)
{
HANDLE hFile = hFile1;
//HANDLE hFile = hFile2;
FILE_BASIC_INFO fdi{};
fdi.FileAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_NORMAL;
BOOL fResult = SetFileInformationByHandle(hFile,
FileBasicInfo,
&fdi,
sizeof(FILE_BASIC_INFO));
if (fResult)
{
// File will be deleted upon CloseHandle.
_tprintf(TEXT("SetFileInformationByHandle marked tempfile for deletion\n"));
// ...
// Now use the file for whatever temp data storage you need,
// it will automatically be deleted upon CloseHandle or
// application termination.
// ...
}
else
{
_tprintf(TEXT("error %lu: SetFileInformationByHandle could not mark tempfile for deletion\n"),
GetLastError());
}
CloseHandle(hFile);
// At this point, the file is closed and deleted by the system.
}
else
{
_tprintf(TEXT("error %lu: could not create tempfile\n"),
GetLastError());
}
//...
}
I have mapped a file of unknown size (around 4-6 GiB) in Windows platform and got a pointer to the start of the file data returned from the MapFileView function. But how can I know that I have reached the end of the file when I access the data using the pointer sequentially?
Here is the code I have so far written and it successfully maps the file and returns the pointer:
#include <Windows.h>
#include <stdio.h>
#include <inttypes.h>
int main()
{
HANDLE hFile = CreateFile("Test.bin",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (!hFile)
{
printf("Could not create file (%lu).\n", GetLastError());
exit(1) ;
}
HANDLE hMapFile = CreateFileMappingA(hFile,
NULL,
PAGE_READWRITE,
0,
0,
NULL);
if (!hMapFile)
{
printf("Could not create file mapping object (%lu).\n", GetLastError());
CloseHandle(hFile);
exit(1);
}
int32_t* pBuf = (int32_t*) MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if (!pBuf)
{
printf("Could not map file (%lu).\n", GetLastError());
CloseHandle(hFile);
CloseHandle(hMapFile);
exit(1);
};
UnmapViewOfFile(pBuf);
CloseHandle(hFile);
CloseHandle(hMapFile);
exit(0);
}
So I wanted to read equal sized different parts of the file simultaneously in multiple threads. I believe mapped file is the right choice for this purpose. Advice about any other faster and possible approaches is highly appreciated.
I have researched some similar questions in the forum and I suppose this is the closest topic I could find:
Read all contents of memory mapped file or Memory Mapped View Accessor without knowing the size of it
But this answer is using C# and is not written using the WinAPI, therefore, I couldn't understand their process.
Thanks in advance :)
Call GetFileSizeEx to get the size of a file, and use this in combination with the base address and the current read address to determine where the end address is.
I encountered code similar to this (stripped down for MCVE):
HANDLE hFile = CreateFileW(argv[1], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
// Note: FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH are not present
DWORD dwWritten;
WCHAR wBOM = 0xFEFF, wString[100] = L"Hello World!";
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
WriteFile(hFile, &wBOM, sizeof(WCHAR), &dwWritten, NULL);
WriteFile(hFile, wString, wcslen(wString) * sizeof(WCHAR), &dwWritten, NULL);
FlushFileBuffers(hFile);
CloseHandle(hFile);
The last part struck me as pedantic since I had the impression that calling CloseHandle would flush any buffered output to disk (similar to fclose(FILE *), where it is explicitly documented by the C Standard that buffers will be flushed). However, I wasn't able to find this information in the documentation for CloseHandle on MSDN.
So, is the call to FlushFileBuffers immediately before closing the file handle necessary to avoid discarding buffered output?
Closing the handle does not discard unflushed updates, but it does not flush them either.
FlushFileBuffers() is useful if you want to force flushing before CloseHandle() because the latter does not flush the buffers automatically. However, if you really need direct writes, you must open the handle with FILE_FLAG_WRITE_THROUGH.
If you do not read direct writes, then flushing is not necessary either before closing the handle or at any point of the life of the handle.
windows 7
I have built a project in C to make a dll, whcih could be used in a big program written by python.
static HANDLE hCom = INVALID_HANDLE_VALUE;
unsigned int g_dldtool_exit_code = 0;//can not be written by other threads.
hCom = CreateFile( commPort,
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // overlapped I/O
NULL // hTemplate must be NULL for comm devices
);
if (hCom == INVALID_HANDLE_VALUE) {
// Handle the error.
TRACE ("CreateFile failed with error %d", GetLastError());
g_dldtool_exit_code = 1;
goto _exit;
}
if (hCom != INVALID_HANDLE_VALUE) {
unconfig_serial_port();
fSuccess = CloseHandle(hCom);
I have used
if (hCom != INVALID_HANDLE_VALUE) {
unconfig_serial_port();
fSuccess = CloseHandle(hCom);
to close the serial port, but the if condition can not be meet every time program goes here, so the serial port can not be closed.
When I annotate the if condition, error occurs: ERROR showed when building dll
How could I close the
serial port?
The full code could be download here:
https://www.dropbox.com/s/kk2sc3r6pmmh7tt/download_main.c?dl=0
The error you are reporting seems to be due to a problem in the syntax.
Maybe when you comment out the "if" statement you remove a open bracket "{" but do not remove the close bracket "}".
Concerning why the code does not meet the if statement condition, it is difficult to say from those pieces of code.
I am trying to remove short name of a file in NTFS. I am testing it on Windows 7. I am running my process as an administrator.
Here is my code:
HANDLE hFile;
DWORD error = NO_ERROR;
hFile = fh = CreateFileA(name,
GENERIC_ALL,
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if(hFile == NULL || hFile == INVALID_HANDLE_VALUE)
{
error = GetLastError();
if(GetLastError() == ERROR_ACCESS_DENIED)
printf("File Access Denied.\n");
if(GetLastError() == ERROR_FILE_NOT_FOUND)
printf("File not found.\n");
return error;
}
SetLastError(NO_ERROR);
ModifyPrivilege(SE_RESTORE_NAME, TRUE);
SetLastError(NO_ERROR);
SetFileShortNameW(hFile, L""); // As per MSDN, It will work only in windows 7 and above
error = GetlastError(); // returns 1314 error
ModifyPrivilege(SE_RESTORE_NAME, FALSE);
CloseHandle(hFile);
Code for ModifyPrivilege() is same as on MSDN:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa387705(v=vs.85).aspx
I am making sure that I have SE_RESTORE_NAME privilege (using process explorer for this). Above code does not generate any error but when I look at mft record of the file in hex editor, Short file name is still there i.e. MFT record has two $30 File name attributes, one for full name and other for short name.
I want to know if my code is wrong or some thing else that I have to do? Why does not SetFileShortNameEx function does not any effect in this case?
You need to add the privilege before you call CreateFile.
Your error handling is a bit messed up too. There's no need for any calls to SetLastError. You simply need to check the return values of the API call before you call GetLastError. Only call GetLastError if the docs say that it has meaning. In the case of SetFileShortName, as is the case for many API calls, you only call GetLastError when the API call returns FALSE. So you should write:
if (!SetFileShortNameW(hFile, L""))
{
error = GetLastError();
// ...
}