My goal is to achieve the following:
I want to read a file from disk (let's say it's an image file) and to write it into shared memory so I can read it from the shared memory from another process. First I followed this msdn tutorial to create a simple shared memory implementation to contain a string. It works fine.
Then I found a way to read the image from disk. The implementation is as follows:
std::ifstream fin("path/to/img.png", std::ios::in | std::ios::binary);
std::ostringstream oss;
oss << fin.rdbuf();
std::string data(oss.str());
So now I have a std::string
containing my data The data.length()
indicates that the file I've read is successfully stored in there. In the msdn example, the type of the MapViewOfFile
result is LPTSTR
, so I looked for a way to cast the std::string
I have to LPTSTR
, which is as far I understand a const wchar_t*
. I do this as follows:
std::wstring widestr = std::wstring(data.begin(), data.end());
const wchar_t* widecstr = widestr.c_str();
But if I now check _tcslen(widecstr)
the result is 4
. So I guess what I tried to do doesn't work. I also found this quote on another SO question:
Notice: A std::string is suitable for holding a 'binary' buffer, where a std::wstring is not!
(Source) This makes it sound like I can't store the file data the way I tried.
So my question is: Did I just did a mistake somewhere or is my approach flawed? Maybe I need to use another file type for the result of MapViewOfFile
? Maybe I need to initialy load the file into another type?
I wouldn't provide a full-fledged answer as I don't have an MCVE at hand. However, the OP asked for more clarification and, concerning
CopyMemory()
I found some things worth to be noted (and it was a bit too long to write a comment only about this).CopyMemory()
is nothing especially dedicated to memory mapped files. It's just a function to copy data to destination from source with a size in bytes.While googling for
CopyMemory()
I stumbled over "CopyMemory()
vs.memcpy()
" and found an as nice as short answer on GameDev:So, here we are:
std::memcpy()
For the special case of (potentially) overlapping source/destination ranges,
memcpy()
has a "sibling"memmove()
. In this case of memory mapped files, I don't believe that source and destination can ever overlap. So, thememcpy()
might be fine (and potentially even faster thanmemmove()
.)So, it isn't the
CopyMemory()
which provides the "Memory Mapped File Access Magic". This already happened in another function call which is surely in the source code of OP but not mentioned in the question:MapViewOfFile()
Hence, on success, the
MapViewOfFile()
returns a pointer to the memory where file has been mapped to. Read/write access can be done afterwards like any other process memory access – via assignment operator, viamemcpy()
(orCopyMemory()
), or what ever else is imaginable.Finally, the answer to the add-on question of OP:
Reading can be done in the exact same manner except that pointer to map view becomes source and local buffer becomes destination. But how to determine size? This issue is actually more general: How many bytes are occupied by data with variable length? There are two typical answers in C/C++:
std::string
,std::vector
, etc.)In the specific case of OP, the first option is probably more reasonable. So, the size of pay-load data (the image) might be stored in the memory mapped file as well. On the reader side, first the size is evaluated (which has to have a certain
int
type and hence a known number of bytes), and the size is used to copy the pay-load data.Hence, on writer side it could look like this:
On reader side it could look like this:
Please, note that
&data[0]
provides the same address likedata.data()
. Prior C++ 17, there is no non-const version ofstd::string::data()
, hence the hack withstd::string::operator[]()
which has a non-const version.