Как создать виртуальный файл? - PullRequest
14 голосов
/ 17 января 2010

Я хотел бы смоделировать файл, не записывая его на диск.У меня есть файл в конце моего исполняемого файла, и я хотел бы указать его путь к DLL.Конечно, поскольку у него нет реального пути, я должен его подделать.

Сначала я попытался использовать именованные каналы в Windows для этого.Это позволило бы указать путь, такой как \\. \ Pipe \ mymemoryfile, но я не могу заставить его работать, и я не уверен, что dll будет поддерживать путь, подобный этому.GetMappedFileName.Могут ли они быть использованы для имитации файла в фрагменте другого?Я не уверен, что это то, что делает этот API.

То, что я пытаюсь сделать, похоже на boxedapp.Есть идеи о том, как они это делают?Я предполагаю, что это что-то вроде перехвата API (например, Detour), но это было бы много работы.Есть ли другой способ сделать это?

Почему?Я заинтересован в этом конкретном решении, потому что я хотел бы скрыть данные и в интересах распространения только одного файла, а также по вызывающим причинам заставить его работать таким образом;) Я согласен, что копирование данных во временный файл будет работатьи будет гораздо более простым решением.

Ответы [ 12 ]

6 голосов
/ 14 ноября 2011

Используйте BoxedApp и не волнуйтесь.

5 голосов
/ 17 января 2010

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

Если вы придерживаетесь поведения, похожего на файл, лучше всего всегда использовать файл. В Windows вы можете передать FILE_ATTRIBUTE_TEMPORARY в CreateFile в качестве подсказки системе, чтобы избежать сброса данных на диск при наличии достаточного объема памяти.

Если вы беспокоитесь о снижении производительности записи на диск, вышеприведенного должно быть достаточно, чтобы избежать влияния на производительность в большинстве случаев. (Если в системе недостаточно памяти для принудительного вывода файловых данных на диск, возможно, в любом случае она также сильно поменяется местами - у вас уже есть проблема с производительностью.)

Если вы пытаетесь избежать записи на диск по какой-либо другой причине, вы можете объяснить, почему? В общем, довольно трудно остановить попадание данных на диск - например, пользователь всегда может перевести компьютер в спящий режим.

5 голосов
/ 19 января 2010

Вы можете хранить данные в потоке NTFS. Таким образом, вы можете получить реальный путь, указывающий на ваши данные, которые вы можете дать своей DLL в виде

x:\myfile.exe:mystreamname

Это работает точно так же, как обычный файл, однако это работает, только если используемая файловая система NTFS. Это стандартно для Windows в настоящее время, но, конечно, это не вариант, если вы хотите поддерживать более старые системы или хотели бы иметь возможность запускать это с USB-флешки или подобного. Обратите внимание, что любые потоки, присутствующие в файле, будут потеряны, если файл будет отправлен как вложение в почту или просто скопирован из раздела NTFS в раздел FAT32.

Я бы сказал, что наиболее совместимым способом было бы записать ваши данные в реальный файл, но вы, конечно, можете сделать это одним способом в системах NTFS и другим способом в системах FAT. Я рекомендую против этого из-за дополнительной сложности. Разумеется, правильным способом было бы распространять ваши файлы отдельно, но, поскольку вы указали, что вам это не нужно, вам следует в этом случае записать его во временный файл и указать dll путь к этому файлу. Убедитесь, что вы записали временный файл во временный каталог пользователя (вы можете найти путь, используя GetTempPath в C / C ++).

Другой вариант - написать драйвер фильтра файловой системы, но я настоятельно рекомендую эту дорогу. Такого рода побеждает и цель использования одного файла ...

Кроме того, если вам нужен только один файл для распространения, как насчет использования zip-файла или установщика?

3 голосов
/ 17 января 2010

Поскольку у вас нет контроля над DLL, вы должны предположить, что DLL ожидает фактический файл. Это, вероятно, в какой-то момент делает такое предположение, поэтому именованные каналы не работают на вас.

Самое простое решение - создать временный файл во временном каталоге, записать данные из вашего EXE-файла во временный файл и затем удалить временный файл.

Есть ли причина, по которой вы встраиваете этот «псевдофайл» в конец вашего EXE-файла, а не просто распространяете его с нашим приложением? Очевидно, вы уже распространяете эту стороннюю DLL-библиотеку вместе с вашим приложением, так что, похоже, еще один файл не причинит вам вреда?

Другой вопрос, будут ли эти данные меняться? То есть вы рассчитываете записать данные этого «псевдо-файла» в ваш EXE-файл? Я не думаю, что это будет хорошо работать. Обычные пользователи могут не иметь права на запись в EXE-файл, что может привести к сбою антивирусных программ.

И никакие CreateFileMapping и GetMappedFileName определенно не будут работать, так как они не дают вам имя файла, которое может быть передано в CreateFile. Если бы вы могли как-то заставить эту DLL принять РУЧКУ, тогда это сработало бы.

И я бы даже не стал перехватывать API. Просто передайте DLL путь к точному файлу.

1 голос
/ 19 января 2010

Пожалуйста, объясните, почему вы не можете извлечь данные из вашего EXE-файла и записать его во временный файл. Многие приложения делают это - это классическое решение этой проблемы.

Если вам действительно необходимо предоставить «виртуальный файл», возможно, самым чистым решением является драйвер фильтра файловой системы. «чистый» не означает «хороший» - фильтр является полностью документированным и поддерживаемым решением, поэтому он чище, чем перехват API, внедрение и т. д. Однако фильтры файловой системы не легки.

OSR Online - лучшее место для поиска информации о файловой системе Windows. В списке рассылки NTFSD разработчики файловой системы тусуются.

1 голос
/ 19 января 2010

Чтение вашего вопроса заставило меня задуматься: если вы можете притвориться, что область памяти является файлом и имеет своего рода «виртуальный путь» к нему, то это позволит загрузить DLL непосредственно из памяти, что LoadLibrary запрещает дизайн, спрашивая имя пути. И именно поэтому люди пишут собственный PE-загрузчик, когда хотят этого достичь.

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

Использование Detours подразумевает, что вам придется копировать все, что делает перехваченная функция DLL, за исключением получения данных из реального файла; следовательно, это не универсально. Или, что еще сложнее, давайте представим, что DLL использует fopen; затем вы предоставляете свой собственный fopen, который обнаруживает особый паттерн в пути, и вы имитируете внутренние компоненты C времени выполнения ... Хм, действительно ли это стоит всей боли? : D

0 голосов
/ 24 января 2010

Почему бы просто не добавить его в качестве ресурса - http://msdn.microsoft.com/en-us/library/7k989cfy(VS.80).aspx - так же, как добавить иконку.

0 голосов
/ 24 января 2010

Вы пытались использовать префикс \? \ При использовании именованных каналов? Многие API поддерживают использование \? \ Для прямой передачи оставшейся части пути без разбора / модификации.

http://msdn.microsoft.com/en-us/library/aa365247(VS.85,lightweight).aspx

0 голосов
/ 23 января 2010

Я предполагаю, что эта DLL не может взять поток? Почти просто спросить НО, если это возможно, вы можете просто использовать это.

0 голосов
/ 21 января 2010

Откройте файл с именем «NUL:» для записи. Это доступно для записи, но данные молча отбрасываются. Вроде как / dev / null из * nix fame.

Вы не можете отобразить это в памяти. Отображение памяти подразумевает доступ для чтения / записи, а NUL только для записи.

...