【问题标题】:How to create a virtual file?如何创建虚拟文件?
【发布时间】:2011-01-06 01:22:37
【问题描述】:

我想模拟一个文件而不将其写入磁盘。我的可执行文件末尾有一个文件,我想将其路径提供给 dll。当然,既然它没有真正的路径,我只好伪造它。

我首先尝试在 Windows 下使用命名管道来做到这一点。这将允许像 \\.\pipe\mymemoryfile 这样的路径,但我无法使其工作,而且我不确定 dll 是否支持这样的路径。

其次,我找到了 CreateFileMapping 和 GetMappedFileName。它们可以用来模拟另一个片段中的文件吗?我不确定这就是这个 API 的作用。

我正在尝试做的似乎类似于 boxedapp。关于他们如何做到这一点的任何想法?我想这有点像 API 拦截(像 Detour ),但这将是很多工作。还有其他方法吗?

为什么?我对这个特定的解决方案很感兴趣,因为我想隐藏数据并为了只分发一个文件的好处,但也因为令人讨厌的原因使它以这种方式工作;) 我同意将数据复制到临时文件是可行的,并且是一种更简单的解决方案。

【问题讨论】:

    标签: c++ windows winapi named-pipes


    【解决方案1】:

    使用BoxedApp,别担心。

    【讨论】:

      【解决方案2】:

      您可以将数据存储在 NTFS 流中。这样,您可以获得指向您的数据的真实路径,您可以以

      的形式将其提供给您的 dll
      x:\myfile.exe:mystreamname
      

      这与普通文件完全一样,但它仅在使用的文件系统是 NTFS 时才有效。这是当今 Windows 下的标准,但如果您想支持旧系统或希望能够从 USB 棒或类似设备上运行它,这当然不是一个选项。请注意,如果文件作为邮件附件发送或简单地从 NTFS 分区复制到 FAT32 分区,则文件中存在的任何流都将丢失。

      我会说最兼容的方式是将数据写入实际文件,但您当然可以在 NTFS 系统上使用一种方式,而在 FAT 系统上使用另一种方式。我建议不要这样做,因为它增加了复杂性。当然,适当的方法是单独分发您的文件,但是由于您已经表明您不想要这个,所以在这种情况下您应该将它写入一个临时文件并为 dll 提供该文件的路径。确保将临时文件写入用户的临时目录(您可以在 C/C++ 中使用 GetTempPath 找到路径)。

      您的另一个选择是编写文件系统过滤器驱动程序,但我强烈建议不要这样做。这也违背了使用单个文件的目的......

      另外,如果您只想分发一个文件,使用 zip 文件或安装程序怎么样?

      【讨论】:

      • 您是如何分发文件的?我会说压缩或复制 exe 会使 NTFS 流消失?
      • @Gregory:是的。问题中的用例并不是很清楚,但我同意使用流很可能不是 OP 的一个选项——希望我的回答中也清楚地表明了这一点。我试图在答案中强调的要点是,使用实际文件是最好的选择。
      • 这是一个非常有趣的想法。太糟糕了,它只适用于ntfs。由于没有完美的答案,这个是最好的。
      【解决方案3】:

      管道用于同时运行的进程之间的通信。它们不存储数据以供以后访问,并且它们的语义与文件不同(例如,您不能查找或回绕管道)。

      如果您追求类似文件的行为,最好的选择永远是使用文件。在 Windows 下,您可以将FILE_ATTRIBUTE_TEMPORARY 传递给CreateFile 作为系统提示,以避免在内存充足的情况下将数据刷新到磁盘。

      如果您担心写入磁盘会影响性能,那么在大多数情况下,以上内容应该足以避免性能影响。 (如果系统的内存足够低,无法将文件数据强制输出到磁盘,那么无论如何它可能也在大量交换——你已经遇到了性能问题。)

      如果您出于其他原因试图避免写入磁盘,您能解释一下原因吗?一般来说,要阻止数据进入磁盘是相当困难的——例如,用户总是可以让机器休眠。

      【讨论】:

      • 文件将直接嵌入到 .exe 中,但 dll 只接受路径作为输入(它不能从 istream 或类似的东西加载)
      【解决方案4】:

      由于您无法控制 DLL,因此您必须假设 DLL 需要一个实际文件。它可能在某些时候做出了这样的假设,这就是命名管道对您失败的原因。

      最简单的解决办法是在临时目录下创建一个临时文件,将EXE中的数据写入临时文件,然后删除临时文件。

      您是否有理由将这个“伪文件”嵌入到您的 EXE 的末尾,而不是仅仅通过我们的应用程序分发它?您显然已经在您的应用程序中分发了这个第三方 DLL,所以再添加一个文件似乎不会对您造成伤害?

      另一个问题,这些数据会改变吗?那就是你希望在你的EXE中写回这个“伪文件”的数据?我认为这不会很好。标准用户可能没有对 EXE 的写入权限,这可能会导致反病毒疯狂。

      并且没有 CreateFileMapping 和 GetMappedFileName 肯定不起作用,因为它们没有给你一个可以传递给 CreateFile 的文件名。如果你能以某种方式让这个 DLL 接受 HANDLE,那么它会起作用。

      而且我什至不会为 API 拦截而烦恼。只需为 DLL 提供一个实际文件的路径即可。

      【讨论】:

        【解决方案5】:

        阅读你的问题让我想到:如果你可以假装一个内存区域是一个文件并且有一种“虚拟路径”,那么这将允许直接从内存加载一个 DLL,这是 LoadLibrary 禁止的通过询问路径名进行设计。这就是为什么人们在想要实现这一目标时编写自己的 PE 加载器的原因。

        我会说您无法通过文件映射实现您想要的:文件映射的目的是将文件的一部分视为物理内存,而您想要的是倒数。

        使用 Detours 意味着您必须复制被拦截的 DLL 函数所做的一切,除了从真实文件中获取数据;因此它不是通用的。或者,更复杂的是,让我们假设 DLL 使用fopen;然后你提供你自己的fopen 来检测路径中的特殊模式,然后你模仿 C 运行时内部......嗯,这真的值得所有的痛苦吗? :D

        【讨论】:

        • 因为 c 运行时是 w32 函数的外观,我不需要覆盖每个使用文件的函数,但低级函数。
        【解决方案6】:

        请解释为什么不能从 EXE 中提取数据并将其写入临时文件。许多应用程序都这样做——这是解决这个问题的经典解决方案。

        如果您真的必须提供“虚拟文件”,最干净的解决方案可能是文件系统过滤驱动程序。 “干净”并不意味着“好”——过滤器是一个完整记录和支持的解决方案,因此它比 API 挂钩、注入等更干净。但是,文件系统过滤器并不容易。

        OSR Online 是查找 Windows 文件系统信息的最佳位置。 NTFSD 邮件列表是文件系统开发人员常去的地方。

        【讨论】:

          【解决方案7】:

          如何使用某种 RamDisk 并将文件写入该磁盘?我自己也尝试了一些 ramdisk,虽然没有找到好的,请告诉我你是否成功。

          【讨论】:

            【解决方案8】:

            好吧,如果你需要在你的 exe 中分配虚拟文件,你需要创建一个足够大的向量、流或字符数组来保存你想要写入的所有虚拟数据。

            这是我能想到的唯一解决方案,无需对磁盘进行任何 I/O(即使您不写入文件)。

            如果您需要保留类似路径语法的文件,只需编写一个模仿该行为的类,而不是写入文件写入内存缓冲区。这很简单。记住 KISS。

            干杯

            【讨论】:

              【解决方案9】:

              打开名为“NUL:”的文件进行写入。它是可写的,但数据会被默默地丢弃。有点像 *nix 声名鹊起的 /dev/null。

              你不能记忆映射它。内存映射意味着读/写访问,而 NUL 是只写的。

              【讨论】:

                【解决方案10】:

                我猜这个 dll 不能接受流?问它几乎很简单,但你是否可以使用它。

                【讨论】:

                • 这是一个我不拥有的dll,我也没有它的源代码,它只有一个带路径的加载文件api。所以我无法改变这一点。
                【解决方案11】:

                您是否尝试过在使用命名管道时使用 \?\ 前缀?许多 API 支持使用 \?\ 直接传递路径的其余部分,无需任何解析/修改。

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

                【讨论】:

                  【解决方案12】:

                  为什么不直接将其添加为资源 - http://msdn.microsoft.com/en-us/library/7k989cfy(VS.80).aspx - 就像添加图标一样。

                  【讨论】:

                    猜你喜欢
                    • 2016-09-29
                    • 1970-01-01
                    • 2015-08-25
                    • 2015-02-27
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多