1

I have a Memory mapped file and corresponding MapViewOfFile handle. The memory mapped file will contain data in two parts:

  1. unsigned int specifying the length of actual data
  2. Actual relevant data

For e.g. if the length of my actual data is 10 characters, the memory mapped file would be like:

10
abcdefghij

where abcdefghij is the data I want and there will be a newline b/w the length number and data. I am also free to use any other delimiter if needed.

Now I want to read the unsigned int first in order to be able to read the actual data. I am thinking of memcpy but I am not sure how can I get the exact unsigned int value as I think memcpy copies character by character. How can I extract 10 as it is from the content?

Navjot Singh
  • 678
  • 7
  • 18
  • 4
    When you say the data starts with an unsigned int, you mean ascii-encoded digits then, and not a big- or little-endian integer value? But then, what if the data after the lenght starts with a number, how do you make the distinction? – jdehesa Sep 19 '19 at 13:21
  • @jdehesa is absolutely right. If you have control over the file, I recommend specifying "the first x bytes of the file is the length of the data" or "the ascii-encoded digits are followed by a newline character". – joshwilsonvu Sep 19 '19 at 13:24
  • The source of this memory mapped file will be a another program which will just copy a string as byte array into the shared memory – Navjot Singh Sep 19 '19 at 13:25
  • Can you guarantee that the actual data will not begin with digit characters? – joshwilsonvu Sep 19 '19 at 13:26
  • No I cannot guarentee that – Navjot Singh Sep 19 '19 at 13:27

1 Answers1

1

You can do like so:

#include "windows.h"
#include <iostream>

int main() {
    const size_t buffer_size = 4098;
    const char* name = "my_shared_memory"; //sm name
    HANDLE file = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, buffer_size, name);
    LPVOID region = MapViewOfFile(file, FILE_MAP_ALL_ACCESS, 0, 0, buffer_size);

    const char* const msg = "this is my data"; //this is the string you want to pass
    const int msg_size = strlen(msg) + 1; //this is the size of the string data with \0
    const int total_size = msg_size + sizeof(int); //the total size of your data: the size of the string and the string by itself
    char* const data = (char*)malloc(total_size); //get some memory to place this data
    ((int*)data)[0] = msg_size; //set the first part of the data with the string msg size
    memcpy(data + sizeof(int), msg, msg_size); //set the msg by it self just after the size

    CopyMemory(region, data, total_size); //put on sm

    const int retrieved_size = ((int*)region)[0]; //retrieves the size of the msg from the sm
    char* const retrieved_msg = (char*)malloc(retrieved_size); //alloc some space for receive the msg with the retrieved size
    memcpy(retrieved_msg, (char*)region + sizeof(int), retrieved_size); //set the msg in the previous allocated memory
    std::cout << retrieved_msg << std::endl; //prints the msg

    free(data);
    free(retrieved_msg);
}

In this question you have some solutions to check for endianess. Then you can use one more byte to store this information if necessary. If endianess is different, you can swap bytes.


Solution for Josh comment:

For ASCII encoded size, instead of putting on memory the size int binary encoded, you can save as if it were a string:

const int max_digits_size = 3;
char number[max_digits_size + 1];
sprintf(number, "%d", msg_size);
//your total_size is now (max_digits_size + 1) + msg_size

//first you retrieve from sm the number as string in number_memcopied var, then you convert:
const int retrieved_size = strtol(number_memcopied, NULL, 10);
João Paulo
  • 6,300
  • 4
  • 51
  • 80
  • This reads a binary encoding of the number when the file format specifies that the number will be ascii-encoded. – joshwilsonvu Sep 19 '19 at 13:58
  • 1
    Works totally fine but I am not sure what @JoshWilson intends. The program does what I asked for. – Navjot Singh Sep 19 '19 at 14:10
  • If you get exactly the code above and replace `"this is my data"` by `"{1.3.4.5.10.1.1 : [ok, string]}"`, it's going to work. Also checked the above code with string starting with numbers and also worked. Check if you're shifting the right size when setting the data buffer. The random number could be some memory trash. Check if you're considering the `\0` char when dealing with strings. It's about not getting the right size in the right place piece of memory. – João Paulo Sep 19 '19 at 14:56
  • Use visual studio memory window to help you inspecting the data buffer. – João Paulo Sep 19 '19 at 15:02