winapi — C ++ Считать файл с диска и записать его в общую память

Моя цель — добиться следующего:

Я хочу прочитать файл с диска (скажем, это файл изображения) и записать его в общую память, чтобы я мог прочитать его из общей памяти из другого процесса.
Сначала я последовал этот MSDN учебник создать простую реализацию совместно используемой памяти, содержащую строку. Работает нормально.

Тогда я нашел способ прочитать образ с диска. Реализация заключается в следующем:

std::ifstream fin("path/to/img.png", std::ios::in | std::ios::binary);
std::ostringstream oss;
oss << fin.rdbuf();
std::string data(oss.str());

Так что теперь у меня есть std::string содержащий мои данные data.length() указывает, что файл, который я прочитал, успешно хранится там. В примере msdn тип MapViewOfFile результат LPTSTRЯ искал способ разыграть std::string Мне пришлось LPTSTRнасколько я понимаю const wchar_t*, Я делаю это следующим образом:

std::wstring widestr = std::wstring(data.begin(), data.end());
const wchar_t* widecstr = widestr.c_str();

Но если я сейчас проверю _tcslen(widecstr) результат 4, Так что я думаю, что я пытался сделать, не работает. Я также нашел эту цитату на другом вопросе:

Примечание: std :: string подходит для хранения двоичного буфера, а std :: wstring — нет!

(ИсточникЭто звучит так, будто я не могу сохранить данные файла так, как я пытался.

Итак, мой вопрос: я только что где-то допустил ошибку или мой подход некорректен? Может быть, мне нужно использовать другой тип файла для результата MapViewOfFile? Может быть, мне нужно изначально загрузить файл в другой тип?

2

Решение

Я бы не стал давать полноценный ответ, так как у меня нет MCVE под рукой. Однако ФП попросил дать дополнительные разъяснения и, в отношении CopyMemory() Я нашел некоторые вещи, которые стоит отметить (и было слишком долго писать комментарии только по этому поводу).

CopyMemory() ничего особенно не посвящено файлам, отображенным в память. Это просто функция для копирования данных в пункт назначения из источника с размером в байтах.

Пока гуглил CopyMemory() Я споткнулсяCopyMemory() против memcpy()«и нашел короткий ответ на Разработка игр:

Прямо из WINBASE.H

#define CopyMemory RtlCopyMemory

Тогда прямо из WINNT.H

#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length))

Итак, мы здесь:

std::memcpy()

Определено в заголовке <cstring>

void* memcpy( void* dest, const void* src, std::size_t count );

Копии count байты от объекта, на который указывает src к объекту, указанному dest, Оба объекта интерпретируются как массивы unsigned char,

Если объекты перекрываются, поведение не определено.

Для особого случая (потенциально) перекрывающихся диапазонов источника / назначения, memcpy() имеет «родного брата» memmove(). В этом случае файлы с отображением в памяти, я не верю, что источник и назначение могут когда-либо пересекаться. Итак memcpy() может быть хорошо (и, возможно, даже быстрее, чем memmove().)

Так что это не CopyMemory() который обеспечивает «Магию доступа к файлу с отображением в памяти». Это уже произошло в другом вызове функции, который обязательно находится в исходном коде OP, но не упоминается в вопросе:

MapViewOfFile()

Сопоставляет представление файла с адресным пространством вызывающего процесса.

Возвращаемое значение

Если функция завершается успешно, возвращаемое значение является начальным адресом отображенного представления.

Следовательно, в случае успеха MapViewOfFile() возвращает указатель на память, в которую был отображен файл. Доступ на чтение / запись может быть сделан впоследствии, как и любой другой доступ к памяти процесса — через оператор присваивания, через memcpy() (или же CopyMemory()) или что еще можно вообразить.

Наконец, ответ на дополнительный вопрос OP:

Как я мог читать данные в строку / байтовый массив на «другой» стороне, где я читал из общей памяти?

Чтение может быть выполнено точно таким же образом, за исключением того, что указатель на представление карты становится источником, а локальный буфер становится местом назначения. Но как определить размер? Эта проблема на самом деле более общая: сколько байтов занимают данные с переменной длиной? В C / C ++ есть два типичных ответа:

  • либо хранить размер данных (например, в std::string, std::vector, так далее.)
  • или как-то отметить конец данных (например, нулевой терминатор в C-строках).

В конкретном случае OP, первый вариант, вероятно, более разумным. Таким образом, размер данных полезной нагрузки (изображения) также может быть сохранен в файле отображения памяти. На стороне читателя, сначала оценивается размер (который должен иметь определенный int тип и, следовательно, известное число байтов), а размер используется для копирования данных полезной нагрузки.

Следовательно, на стороне писателя это может выглядеть так:

/* prior something like
* unsigned char *pBuf = MapViewOfFile(...);
* has been done.
*/
// write size:
size_t size = data.size();
CopyMemory(pBuf, (const void*)&size, sizeof size);
// write pay-load from std::string data:
CopyMemory(pBuf + sizeof size, data.data(), size);

На стороне читателя это может выглядеть так:

/* prior something like
* const unsigned char *pBuf = MapViewOfFile(...);
* has been done.
*/
// read size:
size_t size = 0;
CopyMemory((void*)&size, pBuf, sizeof size);
// In C, I had probably done: size_t size = *(size_t*)pBuf; instead...
// allocate local buffer for pay-load
std::string data(size, '\0');
// read pay-load
CopyMemory(&data[0], pBuf + sizeof size, size);

Пожалуйста, обратите внимание, что &data[0] предоставляет тот же адрес, что и data.data(), До C ++ 17 не существует неконстантной версии std::string::data()отсюда и взлом с std::string::operator[]() которая имеет неконстантную версию.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]