writing in file using threads (WINAPI) - c

Just when I thought I finally understood threads, I got a problem.
In the main thread, I create a mutex using this:
Mutex = CreateMutex(NULL, FALSE, Mutex_Name);
Then, in one of the worker threads (the first one to reach), I have a function that returns a handle to a file by creating it like this:
file_h = CreateFile("The_File.txt",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
The other threads have functions that return a handle to the file by this:
file_h = CreateFile("The_File.txt",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
At the last part, both threads try to write to the file using this function:
int W_to_f(char* str_to_w, HANDLE file)
{
HANDLE mutex = NULL;
DWORD waitcode1;
DWORD dwBytesWrite;
char line[Line_Len];
mutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, LOCK);
if (mutex == NULL)
{
printf("Failed at opening LOCK in write file\n");
return -1;
}
waitcode1 = WaitForSingleObject(mutex, 15000);
if (WAIT_OBJECT_0 != waitcode1)
{
printf("Error when waiting for LOCK in file\n");
return -1;
}
strcpy(line, str_to_w);
while ((Line_Len - (strlen(line) + 1)) > 0)
{
strcat(line, "#");
}
SetFilePointer(file, 0, NULL, FILE_END); //problem?
WriteFile(file, line, strlen(line), &dwBytesWrite, NULL);
WriteFile(file, "\n", 2, &dwBytesWrite, NULL);
if(!ReleaseMutex(mutex))
{
printf("failed release mutex in write_file fun\n");
return -1;
}
return 0;
}
All I want them to do is to write to the file like this:
firststring############
secondstring###########
But, after checking with breakpoints, what I get is that the first one manages to write to file:
firststring###########
But then after the second one writes to the file, it becomes:
癡慩㩤㈱㐳䁀䁀䁀䁀䁀䁀䁀䁀䁀幀搀湩楤㩮㘵㠷䁀䁀䁀䁀䁀䁀䁀䁀䁀
Just one line, it doesn't even write the Chinese after the firststring####.
Should I somehow use SetFilePointer?
Should I CreateFile() in the function using OPEN_EXISTING for each thread?

Related

How can my pipe client wait for the server

I am implementing a named pipe IPC scheme in C running on windows, which is mostly working.
On the client side I create the pipe like this
void CreatePipex(const LPCWSTR pipename, InteruptHandler interruptHandler, unsigned char *USARTData)
{
while (1)
{
pipes [_pipeIndex].handle = CreateFile(
pipename,
GENERIC_READ |
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
// break if pipe was created
if (pipes[_pipeIndex].handle != INVALID_HANDLE_VALUE)
{
wprintf(L"created pipe %s\n", pipename);
break;
}
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
}
// exit if pipe not created and not busy
if (GetLastError() != ERROR_PIPE_BUSY)
{
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
wprintf(L"Could not create %s : %s %d\n",pipename, buf,GetLastError());
//printf("could not create pipe %d\n", lastError);
exit(-1);
}
if (!WaitNamedPipe(pipename, 20000))
{
wprintf(L"Could not open %s: 20 second wait timed out.\n",pipename);
exit(-1);
}
}
DWORD mode = PIPE_NOWAIT;
if (!SetNamedPipeHandleState(pipes[_pipeIndex].handle, &mode, 0, 0))
{
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
wprintf(L"Could not set mode for %s : %s\n", pipename, buf);
exit(-1);
}
But if I run the client without the server the client pipe cannot be created
Could not create \\.\pipe\F0 : The system cannot find the file specified.
Is there a way of getting my client to wait for the server?
You could loop (and sleep) until CreateFile returns something different from ERROR_FILE_NOT_FOUND.

Memory Mapped File changes not reflected in underlying file

I am learning MMF in win32 C.
I can't seem to see what I am missing...
Here is my code:
#include "stdafx.h"
#include <Windows.h>
int main()
{
wchar_t szfilename[] = L"c:\\temp\\mmf.txt";
HANDLE hFile = CreateFile(
szfilename,
GENERIC_READ | GENERIC_WRITE, //dwDesiredAccess
FILE_SHARE_READ | FILE_SHARE_WRITE, //dwShareMode
NULL, //lpSecurityAttributes
CREATE_NEW, //dwCreationDisposition
FILE_ATTRIBUTE_NORMAL, //dwFlagsAndAttributes
NULL); //hTemplateFile
if (hFile == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
if (error != ERROR_FILE_EXISTS)
exit(-1);
}
//Now create the file mapping
HANDLE hMap = CreateFileMapping(
hFile,
NULL, //LPSECURITY_ATTRIBUTES lpAttributes,
PAGE_READWRITE, //DWORD flProtect,
0, //DWORD dwMaximumSizeHigh,
1024, //DWORD dwMaximumSizeLow,
L"myMappingFile"); //LPCTSTR lpName
if (hMap == (HANDLE)ERROR_ALREADY_EXISTS || hMap == NULL)
{
DWORD error = GetLastError();
exit(-2);
}
LPCTSTR pBuf = (LPTSTR)MapViewOfFile(hMap, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
0);
if (pBuf == NULL)
{
printf("Could not map view of file (%d).\n",
GetLastError());
return -2;
}
wchar_t szMsg[] = L"Msg from first process";
CopyMemory((PVOID)pBuf, szMsg, wcslen(szMsg) * sizeof(wchar_t));
UnmapViewOfFile(pBuf);
CloseHandle(hMap);
CloseHandle(hFile);
return 0;
}
I open a file, associate it with a memory mapping and create a view. Then I write data (copy) into the buffer (view) and close things down.
I am trying to figure out why my underlying file (c:\temp\mmf.txt) does not contain the msg after the routine executes. Am I missing something? The file size remains 0.
Here is a snippet of code that demonstrates memory mapping a file. In the end I think you will just benefit from reading the MSDN docs for each API call you are using a little more carefully.
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hFileMapping = NULL;
LPVOID pBase = NULL;
__try
{
hFile = CreateFile(filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(hFile == INVALID_HANDLE_VALUE) __leave;
hFileMapping = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0, 0, NULL);
if(hFileMapping == NULL) __leave;
pFileBase = MapViewOfFile(hFileMapping,
FILE_MAP_READ,
0, 0, 0);
if(pBase == NULL) __leave;
}
__finally
{
if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
if(hFileMapping != NULL) CloseHandle(hFileMapping);
}

Named Pipe communication between service and application

So I have a service which starts at boot time, and I have an application which I have placed in the startup folder.
So the client sometimes connects very late to the server of the named pipe.
Here is my code in my service.
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\popupPipe"),
PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_WAIT,
1, 1024 * 16, 1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
HRESULT
SendMessage(){
if (ConnectNamedPipe(hPipe, NULL) != FALSE) { // wait for someone to connect to the pipe
WriteFile(hPipe, (char *)message->buffer, sizeof(message->buffer), &dwWritten, NULL);
return S_OK;
}
return E_FAIL;
}
and here is the application
hPipe = CreateFile(TEXT("\\\\.\\pipe\\popupPipe"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hPipe == INVALID_HANDLE_VALUE)
return -1;
while (hPipe != INVALID_HANDLE_VALUE)
{
DWORD dwRead;
char buffer[100] = { 0 };
while (ReadFile(hPipe, buffer, sizeof(buffer), &dwRead, NULL) != FALSE);
if (dwRead == sizeof(buffer)) {
dwRead = 0;
buffer[100] = '\0';
temp = &buffer[1];
DisplayPopup(hInstance, cmdShow);
}
}
return 0;
but at the clients end the application always returns INVALID_HANDLE_VALUE
In the service SendMessage is called multiple times so even if it fails the first times it should succeed when the client connects shouldn't it.
You don't check if the creation of the pipe suceeds. Looking at the Microsoft documentation, it probably does not succeed because you mix parameters:
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\popupPipe"),
PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_WAIT,
1, 1024 * 16, 1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
should be:
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\popupPipe"),
PIPE_ACCESS_DUPLEX, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1, 1024 * 16, 1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);

Asynchronous named Windows pipe communication via overlapped IO

I'm using overlapped IO to read and write a single Windows pipe in C code simultantiously. I want to write a synchronous function to read and write data from seperate threads. If you are using synchronous IO you cannot read and write the pipe simultaniously. My client and my server are using the same write/read functions. Time by time my client sends data that is never received by the server. Does anyone have an idea how this could happen? If I use synchronous IO in the client everything works as expected.
The server pipe is opened by the following cmd:
CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
instances, PIPE_BUF_SIZE, PIPE_BUF_SIZE, 0, NULL);
The client pipe is opend this way:
CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
I'm using these read function:
int readBytesPipeCommChannel(PipeCommChannelData* comm, uint32_t* amount)
OVERLAPPED osRead;
memset(&osRead, 0, sizeof(osRead));
osRead.hEvent = comm->readAsyncIOEvent;
int err = 0;
if(!ReadFile(comm->pipeH, comm->receiveBuffer, sizeof(comm->receiveBuffer), amount, &osRead))
{
err = GetLastError();
if (err == ERROR_IO_PENDING)
{
if(WaitForSingleObject(osRead.hEvent, INFINITE))
{
GetOverlappedResult(comm->pipeH, &osRead, amount, TRUE);
}
else
{
CancelIo(comm->pipeH);
return PIPE_EVENT_ERROR;
}
}
else if(err != ERROR_BROKEN_PIPE)
{
return PIPE_READ_ERROR;
}
}
if(err == ERROR_BROKEN_PIPE)
return PIPE_BROKEN_ERR;
return PIPE_OK;
}
And last but not least the write function:
int sendBytesPipeCommChannel(PipeCommChannelData* comm, const uint8_t* bytes, uint32_t amount)
{
OVERLAPPED osWrite;
memset(&osWrite, 0, sizeof(osWrite));
osWrite.hEvent = comm->writeAsyncIOEvent;
uint32_t bytesWritten = 0;
for(uint32_t curPos = 0; curPos < amount; curPos += bytesWritten)
{
if(!WriteFile(comm->pipeH, &bytes[curPos], (amount - curPos), &bytesWritten, &osWrite))
{
if (GetLastError() != ERROR_IO_PENDING)
return PIPE_WRITE_ERR;
if(!WaitForSingleObject(osWrite.hEvent, INFINITE))
{
CancelIo(comm->pipeH);
return PIPE_EVENT_ERROR;
}
}
}
return PIPE_OK;
}
The documentation for ReadFile says:
If hFile was opened with FILE_FLAG_OVERLAPPED, the following conditions are in effect:
The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to get the actual number of bytes read.
This applies even if the operation completes synchronously.

Using ReadFile to read entire PhysicalDrive contents

I am fairly new to C, and I am trying to write a small application that will read the entire raw contents of a drive.
Here is my code;
int main(int argc, char *argv[]) {
HANDLE hFile;
DWORD dwBytesRead;
char buff[512];
hFile = CreateFile("\\\\.\\PhysicalDrive2", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if(hFile == INVALID_HANDLE_VALUE){
printf("%d",GetLastError());
return;
}
SetFilePointer(hFile, 512*0, NULL, FILE_BEGIN);
ReadFile(hFile, buff, 512, &dwBytesRead, NULL);
CloseHandle(hFile);
return 0;
}
How do I put the ReadFile into a loop to read all the data on the drive? I eventually need to save the contents of the buffer to the disk.
Thanks
The loop might look like this:
hFile = CreateFile(...);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error
}
while (true)
{
unsigned char buff[32768]; // needs to be a multiple of sector size
DWORD dwBytesRead;
if (!ReadFile(hFile, buff, sizeof buff, &dwBytesRead, NULL))
{
// handle error
}
if (dwBytesRead == 0)
{
break; // we reached the end
}
// do something with the dwBytesRead that were read
}
CloseHandle(hFile);

Resources