Boost Serialization and Win32 file handle [duplicate] - c++

Is there any way to take advantage of the file creation flags in the Win32 API such as FILE_FLAG_DELETE_ON_CLOSE or FILE_FLAG_WRITE_THROUGH as described here http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx , but then force that handle into a std::ofstream?
The interface to ofstream is obviously platform independent; I'd like to force some platform dependent settings in 'under the hood' as it were.

It is possible to attach a C++ std::ofstream to a Windows file handle. The following code works in VS2008:
HANDLE file_handle = CreateFile(
file_name, GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle != INVALID_HANDLE_VALUE) {
int file_descriptor = _open_osfhandle((intptr_t)file_handle, 0);
if (file_descriptor != -1) {
FILE* file = _fdopen(file_descriptor, "w");
if (file != NULL) {
std::ofstream stream(file);
stream << "Hello World\n";
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
file = NULL;
file_descriptor = -1;
file_handle = INVALID_HANDLE_VALUE;
}
}
This works with FILE_FLAG_DELETE_ON_CLOSE, but FILE_FLAG_WRITE_THROUGH may not have the desired effect, as data will be buffered by the std::ofstream object, and not be written directly to disk. Any data in the buffer will be flushed to the OS when stream.close() is called, however.

Some of these flags are also available when using _fsopen / fopen:
FILE* pLockFile = _fsopen(tmpfilename.c_str(), "w", _SH_DENYWR );
if (pLockFile!=NULL
{
// Write lock aquired
ofstream fs(pLockFile);
}
Here we open the file so when doing a flush, then it writes through (And it is deleted when closed):
FILE* pCommitFile = fopen(tmpfilename.c_str(), "wcD");
if (pCommitFile!=NULL)
{
// Commits when doing flush
ofstream fs(pCommitFile);
}

Related

How to append in file in Windows in UnBuffered mode using CreateFile

Every time my function is getting called it is overwriting to the file. Kindly note I am opening file in unbuffered mode using below flags.
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH
If I am using simple buffered mode it is working fine.
FILE_ATTRIBUTE_NORMAL
I am getting following error in unbuffered mode.
** ERROR ** CreateFile failed: The parameter is incorrect.
Kindly find the code snippets below. This piece of code getting called many times.
HANDLE hFile;
LPCWSTR file_path = convertCharArrayToLPCWSTR(UNBUFFERED_FILE);
hFile = CreateFile(file_path,
FILE_APPEND_DATA,
FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "Unable to open/create file for writing" << std::endl;
PrintError(TEXT("CreateFile failed"));
}
Data *data = new Data();
DWORD dwBytesToWrite = sizeof(Data);
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
bErrorFlag = WriteFile(
hFile, // open file handle
data, // start of data to write
dwBytesToWrite, // number of bytes to write
&dwBytesWritten, // number of bytes that were written
NULL);
if (bErrorFlag == FALSE)
{
std::cout << "Unable to write to file" << std::endl;
PrintError(TEXT("Unable to write to file"));
}
if (dwBytesToWrite != dwBytesWritten)
{
std::cout << "Error in writing: Whole data not written" << std::endl;
PrintError(TEXT("Error in writing: Whole data not written"));
}
CloseHandle(hFile);
.
Kindly suggest if any alternative idea is available.
from NtCreateFile
FILE_NO_INTERMEDIATE_BUFFERING
The file cannot be cached or buffered in a driver's internal
buffers. This flag is incompatible with the DesiredAccess
parameter's FILE_APPEND_DATA flag.
so when you call
CreateFile(file_path,
FILE_APPEND_DATA, // !!
FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_FLAG_NO_BUFFERING /*!!*/| FILE_FLAG_WRITE_THROUGH,
NULL
);
you use FILE_FLAG_NO_BUFFERING (mapped to FILE_NO_INTERMEDIATE_BUFFERING) with FILE_APPEND_DATA - you and must got ERROR_INVALID_PARAMETER. you need remove one flag. i suggest remove FILE_FLAG_NO_BUFFERING flag, because with it you can write only integral of the sector size.

Is there a way to serialize/deserialize a HANDLE in/from a file?

is there a way to serialize a HANDLE in a file?
This is my Handle:
hPipeReadOrWrite = CreateFileA(
TEXT(PIPEPATH), //Pipepath
GENERIC_WRITE, //Access Mode
0, //ShareMode
NULL, //Security Attributes
OPEN_EXISTING, //Action on a File
0, //Type of File
NULL);
I ask this, because I can only open the pipe once. If I could write the Handle in a file (and dont close the Handle) and deserialize it later, then maybe I´m able to write multiple times in the pipe.
My question before was the following: Writing mulitple times in a special (given) pipe C++
I already tried the following, but here I have a file_descriptor instead of a File:
if (hPipeWrite != INVALID_HANDLE_VALUE) {
int file_descriptor = _open_osfhandle((intptr_t)hPipeWrite, 0);
if (file_descriptor != -1) {
FILE* file = _fdopen(file_descriptor, "w");
if (file != NULL) {
std::ofstream stream(file);
stream << "Hello World\n";
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
file = NULL;
file_descriptor = -1;
hPipeWrite = INVALID_HANDLE_VALUE;
}
}
Thanks for your help...

(Windows) Open the same file simultaneously

I am trying to open a file for writing and reading simultaneously, in windows.
I have one program which writes (every one second) to the file and one that reads from it. In unix it works prefectly but it doesn't work in windows (I can't open an already opened file).
I open the file with fopen().
How can I solve this problem?
EDIT2:
check out _fsopen it uses FILE *, and set the share flag accordingly.
EDIT:
First of all, some code: this is how I used to open the file
FILE* f = NULL;
int res = fopen_s(&f, "c:\\temp\\File1.txt", "w");
if (res != 0) return;
while (true) {
Sleep(1000);
fprintf_s(f , "Some data");
}
fclose(f);
The read was in other applicaiton, but it did fscanf instead.
The fixed code:
char d[] = "data";
HANDLE h = CreateFile("c:\\temp\\f.txt", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_ALWAYS, /*FILE_ATTRIBUTE_NORMAL*/ FILE_FLAG_WRITE_THROUGH, NULL);
if (h == INVALID_HANDLE_VALUE) return 0;
DWORD bytesW;
while(true) {
Sleep(100);
WriteFile(h, d, strlen(d), &bytesW, NULL);
}
CloseHandle(h);
return 0;
Both Windows and Linux have a default way of opening a file, which fopen uses by default.
In Windows, that means blocking (only one process can open a file at a time).
In Linux, it means non-blocking.
fopen is a high-level API. To choose yourself the blocking policy on the file, for Windows you should use OpenFile from WinAPI. In particular, have a look at the OF_SHARE_* flags.

How make FILE* from HANDLE in WinApi?

Is there easy way to create FILE* from WinApi HANDLE which points to one end of pipe?
Something like we do in unix: fdopen(fd,<mode>);
You can do this but you have to do it in two steps. First, call _open_osfhandle() to get a C run-time file descriptor from a Win32 HANDLE value, then call _fdopen() to get a FILE* object from the file descriptor.
FILE* getReadBinaryFile(LPCWSTR path) {
HANDLE hFile = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return nullptr;
}
int nHandle = _open_osfhandle((long)hFile, _O_RDONLY);
if (nHandle == -1) {
::CloseHandle(hFile); //case 1
return nullptr;
}
FILE* fp = _fdopen(nHandle, "rb");
if (!fp) {
::CloseHandle(hFile); //case 2
}
return fp;
}
my code for get an open read binary file descriptor.
you should use fclose to close FILE* if you don't need it .
i didn't test for case 1 and 2, so use it at your own risk.
you can't exchange(convert) them.. if you need to have a file with FILE* and HANDLE you need to open it twice

Can I use CreateFile, but force the handle into a std::ofstream?

Is there any way to take advantage of the file creation flags in the Win32 API such as FILE_FLAG_DELETE_ON_CLOSE or FILE_FLAG_WRITE_THROUGH as described here http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx , but then force that handle into a std::ofstream?
The interface to ofstream is obviously platform independent; I'd like to force some platform dependent settings in 'under the hood' as it were.
It is possible to attach a C++ std::ofstream to a Windows file handle. The following code works in VS2008:
HANDLE file_handle = CreateFile(
file_name, GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle != INVALID_HANDLE_VALUE) {
int file_descriptor = _open_osfhandle((intptr_t)file_handle, 0);
if (file_descriptor != -1) {
FILE* file = _fdopen(file_descriptor, "w");
if (file != NULL) {
std::ofstream stream(file);
stream << "Hello World\n";
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
file = NULL;
file_descriptor = -1;
file_handle = INVALID_HANDLE_VALUE;
}
}
This works with FILE_FLAG_DELETE_ON_CLOSE, but FILE_FLAG_WRITE_THROUGH may not have the desired effect, as data will be buffered by the std::ofstream object, and not be written directly to disk. Any data in the buffer will be flushed to the OS when stream.close() is called, however.
Some of these flags are also available when using _fsopen / fopen:
FILE* pLockFile = _fsopen(tmpfilename.c_str(), "w", _SH_DENYWR );
if (pLockFile!=NULL
{
// Write lock aquired
ofstream fs(pLockFile);
}
Here we open the file so when doing a flush, then it writes through (And it is deleted when closed):
FILE* pCommitFile = fopen(tmpfilename.c_str(), "wcD");
if (pCommitFile!=NULL)
{
// Commits when doing flush
ofstream fs(pCommitFile);
}