Search code examples
c++windowswinapishared-memoryfile-mapping

WINAPI Cpp - OpenFileMapping fails with error (2) ERROR_FILE_NOT_FOUND


I'm trying to use WinApi to CreateFileMapping, MapViewOfFile and CopyMemory. It's not showhing me errors and buffor is being filed with my PID

int write_pid_to_memory(const char *t_pid)
{
    _tprintf(TEXT("[write_pid_to_memory] t_pid: (%s).\n"), t_pid);

    HANDLE h_map_file;
    LPCTSTR p_buf;

    h_map_file = CreateFileMapping(
        INVALID_HANDLE_VALUE, // use paging file
        NULL,                 // default security
        PAGE_READWRITE,       // read/write access
        0,                    // maximum object size (high-order DWORD)
        BUF_SIZE,             // maximum object size (low-order DWORD)
        t_name);              // name of mapping object

    if (h_map_file == NULL)
    {
        _tprintf(TEXT("[write_pid_to_memory] Could not create file mapping object (%d).\n"),
                 GetLastError());
        return 1;
    }
    p_buf = (LPTSTR)MapViewOfFile(
        h_map_file,          // handle to map object
        FILE_MAP_ALL_ACCESS, // read/write permission
        0,
        0,
        BUF_SIZE);

    if (p_buf == NULL)
    {
        _tprintf(TEXT("[write_pid_to_memory] Could not map view of file (%d).\n"),
                 GetLastError());

        CloseHandle(h_map_file);

        return 1;
    }

    std::cout << "[write_pid_to_memory] strlen(t_pid) * sizeof(char) " << strlen(t_pid) * sizeof(char) << std::endl;

    CopyMemory((PVOID)p_buf, t_pid, (strlen(t_pid) * sizeof(char)));

    _getch();

    std::cout << "p_buf " << p_buf << std::endl;

    UnmapViewOfFile(p_buf);

    CloseHandle(h_map_file);

    return 0;
}

... but then there is reading from memmory

int access_pid_from_memory()
{

    HANDLE h_map_file;
    LPCTSTR p_buf;

    h_map_file = OpenFileMapping(
        FILE_MAP_ALL_ACCESS, // read/write access
        FALSE,               // do not inherit the name
        t_name);             // name of mapping object

    if (h_map_file == NULL)
    {
        _tprintf(TEXT("[access_pid_from_memory] Could not open file mapping object (%d).\n"),
                 GetLastError());
        return 1;
    }

    p_buf = (LPTSTR)MapViewOfFile(
        h_map_file,          // handle to map object
        FILE_MAP_ALL_ACCESS, // read/write permission
        0,
        0,
        BUF_SIZE);

    if (p_buf == NULL)
    {
        _tprintf(TEXT("[access_pid_from_memory] Could not map view of file (%d).\n"),
                 GetLastError());

        CloseHandle(h_map_file);

        return 1;
    }

    MessageBox(NULL, p_buf, TEXT("[access_pid_from_memory] Process2"), MB_OK);

    UnmapViewOfFile(p_buf);

    CloseHandle(h_map_file);

    return 0;
}

where I get System Error (2) while trying to open Mapping.

My PID: 19516
[access_pid_from_memory] Could not open file mapping object (2).
[write_pid_to_memory] t_pid: (19516).
[write_pid_to_memory] strlen(t_pid) * sizeof(char) 5
p_buf 19516
Envariamental variable = NEW
Env var value length = 3
Env var value compare resault = 0
Mutex created sucesfully

Code of those functions is from https://learn.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory and only thing I've changed is

CopyMemory((PVOID)p_buf, t_pid, (strlen(t_pid) * sizeof(char)));

Instead of

CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));

Where t_pid is just a const char *, becouse I was tired of Windows TCHAR types and I had no clue how to convert DWORD ProcessID to TCHAR to pass it to memcopy.

Well, I'm clueless why I'm unable to open Mapping. Windows is probably beyond me and I have no idea how

TCHAR t_name[] = TEXT("Global\\MyFileMappingObject");

is supposed to be recognised by system to find memory from which I want to read a message.

Whole programm is supposed to lock execution for only one process and if there is a System variable named "SO2" of value "NEW", new process should stop execution of previous process and continoue locking program for himself.
Locking mechanism is with mutex and to find previous porcess ID, I wanted my current process ID to be saved in memory, for next process to read it form, to close it when sys var will be "NEW".
Nothing crazy. All of this in Linux I've done in one day, but Windows is killing me.

Please help

There is main if someone would be intrested:

#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <windows.h>
#include <string>

#include <conio.h>
#include <tchar.h>

#define BUFFER_SIZE 2048
#define ENV_KEY "SO2"
#define ENV_VAL "NEW"

#define BUF_SIZE 256

TCHAR t_name[] = TEXT("Global\\MyFileMappingObject");
HANDLE h_mutex;

int write_pid_to_memory(const char *dw_pid);
int access_pid_from_memory();

int main(int argc, char **argv)
{

    DWORD dw_pid = GetCurrentProcessId();

    std::stringstream stream;
    stream << dw_pid;
    const char *t_pid = stream.str().c_str();

    // int legnth = s_pid.length()
    // const char *t_pid = (char*)malloc( * sizeof(char));

    // const char t_pid = (char)malloc(strlen(dw_pid) * sizeof(char));

    std::cout << "My PID: " << dw_pid << std::endl;

    access_pid_from_memory();
    write_pid_to_memory(t_pid);

    std::string env_val(ENV_VAL);
    char c_buffer[BUFFER_SIZE];
    LPCSTR lp_name = ENV_KEY;
    LPSTR lp_buffer = c_buffer;
    DWORD dw_size = BUFFER_SIZE;
    DWORD get_env_var;

    //Write to memory your pid for other process to access it and close you

    get_env_var = GetEnvironmentVariable(
        lp_name,
        lp_buffer,
        dw_size);

    if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
    {
        std::cout << "Couldn't find envariamental variable \"SO2\"." << std::endl;
    }

    if (BUFFER_SIZE == get_env_var)
    {
        std::cout << "Buffer for function [GetEnvironmentVariable] is too small. Function failed." << std::endl;
    }

    std::cout << "Envariamental variable = " << lp_buffer << std::endl;
    std::string str_buffer(lp_buffer);
    std::cout << "Env var value length = " << str_buffer.length() << std::endl;
    std::cout << "Env var value compare resault = " << str_buffer.compare(env_val) << std::endl;

    HANDLE h_mutex = NULL;

    LPCSTR str = ENV_KEY;

    h_mutex = OpenMutex(
        MUTEX_ALL_ACCESS,
        TRUE,
        str);

    if (NULL != h_mutex)
    {
        if (str_buffer.compare(env_val) == 0)
        {
            //Realease mutex3
            ReleaseMutex(h_mutex);
            //Close previous process
        }
        else
        {

            throw std::runtime_error("Instance of a program is already running");
        }
    }

    h_mutex = CreateMutex(
        NULL,
        FALSE,
        str);

    if (h_mutex == NULL)
    {
        std::cout << "Failed to create mutex: error - " << GetLastError() << std::endl;
        return 1;
    }

    std::cout << "Mutex created sucesfully" << std::endl;

    DWORD dw_wait_res;

    dw_wait_res = WaitForSingleObject(
        h_mutex,   // handle to mutex
        INFINITE); // no time-out interval

    for (;;)
    {
        Sleep(100);
    }

    CloseHandle(h_mutex);
    system("PAUSE");
    return 0;
}

Solution

  • Your logging clearly shows [access_pid_from_memory] occurs before [write_pid_to_memory].

    And we can clearly see in your main() function that it calls access_pid_from_memory() first (which attempts to open the memory map and then closes it), and then afterwards calls write_pid_to_memory() (which creates the memory map and then closes it). Since there is no active handle referring to the mapping, it gets destroyed as soon as write_pid_to_memory() exits.

    So, you are doing operations out of order, which is why OpenFileMapping() is failing. At no point does the mapping actually exist when access_pid_from_memory() is trying to open it.

    You need to do the following instead:

    • in one process, create the mapping first, and leave it open.

    • THEN, in another process, open the mapping while it is still open in the previous process.

    • THEN, use the mapped memory as needed.

    • THEN, close the mapping in both processes.

    There are other issues with your code, too:

    • converting the process ID to a string just to share it. You can share the ID as a binary DWORD instead.

    • access_pid_from_memory() doesn't actually read anything from the mapping (if it were able to open it at all).

    • main() is assigning t_pid to point at dangling memory. The call to stream.str() produces a temporary std::string that is destroyed as soon as c_str() exits.

    • I don't even know what you are attempting to do with your environment variable and mutex, and what that has to do with sharing memory. For purposes of this post, you should remove that code until you have your shared memory working properly.