2010-01-17 91 views
14

我想模擬一個文件而不寫入磁盤。我在可執行文件的末尾有一個文件,我想給它的路徑指向一個dll。當然,因爲它沒有真正的道路,所以我不得不僞造它。如何創建虛擬文件?

我第一次嘗試在Windows下使用命名管道來做到這一點。這將允許像\\。\ pipe \ mymemoryfile這樣的路徑,但是我無法使其工作,並且我不確定該dll是否會支持這樣的路徑。

其次,我發現CreateFileMapping和GetMappedFileName。他們可以用來模擬另一個片段中的文件嗎?我不確定這是API的功能。

我想要做的似乎與boxedapp類似。有關他們如何做的任何想法?我猜這是API截取(Like Detour)之類的東西,但這將是很多工作。還有另一種方法可以做到嗎?

爲什麼?我對這個特定的解決方案很感興趣,因爲我想隱藏數據並且只分發一個文件的好處,但也是爲了使它以這種方式工作的奇怪原因;) 我同意將數據複製到臨時文件會工作併成爲一個更簡單的解決方案。

回答

4

您可以將數據存儲在NTFS流中。這樣,你可以得到指向你的數據,你可以給你的DLL中的

x:\myfile.exe:mystreamname 

這個工作正是像一個正常的文件形式的真實路徑,但它只能工作,如果使用的文件系統是NTFS。這在現在的Windows下是標準的,但如果您想要支持較舊的系統或希望能夠通過USB或類似的方式運行,這當然不是一種選擇。請注意,如果文件作爲郵件附件發送或僅從NTFS分區複製到FAT32分區,則文件中存在的任何流都將丟失。

我想說最兼容的方法是將數據寫入實際的文件,但當然可以在NTFS系統上和FAT系統上執行另一種方式。由於增加了複雜性,我建議不要這樣做。適當的方法是當然分開你的文件,但是由於你已經指出你不想要這個,你應該在這種情況下把它寫到一個臨時文件,並給dll指向那個文件的路徑。確保將臨時文件寫入用戶的臨時目錄(可以在C/C++中使用GetTempPath找到路徑)。

你的其他選擇是編寫一個文件系統過濾驅動程序,但這是我強烈建議的一條道路。這種類型的使用單一文件的目的也是如此...

另外,如果你只想要一個文件分發,怎麼樣使用zip文件或安裝程序?

+0

你究竟如何分配文件?我會說壓縮或複製exe文件會使NTFS流消失? – 2010-01-20 22:17:07

+0

@Gregory:是的。用例在這個問題中並不十分清楚,但我同意使用流可能不是OP的選項 - 希望這在我的答案中也清楚地表明瞭。我試圖在答案中回答的主要觀點是使用實際文件是最佳選擇。 – villintehaspam 2010-01-20 22:41:51

+0

這是一個非常有趣的想法。太糟糕了,它只適用於ntfs。由於沒有完美的答案,這個是最好的。 – 2010-01-25 15:14:22

4

管道用於同時運行的進程之間的通信。它們不會爲稍後的訪問存儲數據,並且它們與文件不具有相同的語義(例如,您不能查找或倒回管道)。

如果您在處理類似文件的行爲,最好的辦法就是使用文件。在Windows下,您可以將FILE_ATTRIBUTE_TEMPORARY傳遞給CreateFile作爲系統提示,以避免在有足夠內存時將數據刷新到磁盤。

如果您擔心寫入磁盤的性能受到影響,上述內容應足以避免在大多數情況下的性能影響。 (如果系統在內存上足夠低以迫使文件數據出現在磁盤上,則無論如何也可能會大量交換 - 您已經遇到了性能問題。)

如果您試圖避免寫入磁盤出於其他原因,你能解釋爲什麼嗎?一般來說,阻止數據永遠不會碰到磁盤是非常困難的 - 例如,用戶總是可以休眠機器。

+0

這些文件將直接嵌入到.exe中,但dll只接受一個路徑作爲輸入(它不能從istream或類似的東西載入) – 2010-01-17 13:01:01

3

由於您無法控制該DLL,因此您必須假定該DLL需要一個實際的文件。它可能在某種程度上作出這種假設,這就是爲什麼命名管道失敗。

最簡單的解決方案是在臨時目錄中創建臨時文件,將數據從EXE寫入臨時文件,然後刪除臨時文件。

是否有一個原因是您在您的EXE結尾處嵌入了這個「僞文件」而不是將其與我們的應用程序一起發佈?你顯然已經在使用你的應用程序發佈這個第三方DLL,所以再多一個文件看起來好像不會傷害你?

另一個問題,這個數據會改變嗎?那是你希望在EXE中寫回這個「僞文件」的數據嗎?我認爲這不會奏效。標準用戶可能沒有對EXE的寫入權限,這可能會驅動防病毒軟件。

並且沒有CreateFileMapping和GetMappedFileName肯定不會工作,因爲它們不會給你一個可以傳遞給CreateFile的文件名。如果你能以某種方式讓這個DLL接受一個HANDLE,那麼這將起作用。

而我甚至不會打擾API截取。只需將DLL移動到一個acutal文件的路徑即可。

1

讀你的問題讓我想:如果你可以假裝內存區域是一個文件,並有一種「虛擬路徑」,那麼這將允許直接從內存中加載一個DLL,這是什麼設計LoadLibrary禁止通過詢問路徑名稱。這就是爲什麼人們想要實現這一目標時自己寫PE加載程序的原因。

我會說你無法實現你想要的文件映射:文件映射的目的是將文件的一部分視爲物理內存,而你想要的是互惠。

使用Detours意味着您將不得不復制攔截的DLL函數執行的所有操作,除非從實際文件獲取數據;因此它不是通用的。或者,甚至更復雜,讓我們假裝DLL使用fopen;那麼你提供了你自己的fopen,它檢測路徑中的特殊模式,並且你模擬了C運行時內部...嗯,它真的值得所有的痛苦? :D

+0

因爲c運行時是w32函數的外觀,所以我會不需要覆蓋每個使用文件的函數,但是需要覆蓋低級別的函數。 – 2010-01-25 12:41:14

0

如何使用某種RamDisk並將文件寫入此磁盤?我自己嘗試過一些ramdisks,雖然從來沒有找到好的,告訴我你是否成功。

0

那麼,如果你需要在你的exe文件中分配虛擬文件,你需要創建一個足夠大的矢量,流或char數組來存放你想寫的所有虛擬數據。

這是我能想到的唯一解決方案,無需對磁盤執行任何I/O(即使您不寫入文件)。

如果您需要保留一個類似路徑語法的文件,只需編寫一個模仿該行爲的類,而不是寫入文件寫入您的內存緩衝區。它很簡單。記住KISS。

乾杯

0

請解釋爲什麼你不能從你的EXE中提取數據,並將其寫入到一個臨時文件。許多應用程序都這樣做 - 這是解決此問題的經典解決方案。

如果您確實需要提供「虛擬文件」,最簡潔的解決方案可能是文件系統過濾驅動程序。 「乾淨」並不意味着「好」 - 過濾器是一個完整的文檔和支持的解決方案,因此它比API掛鉤,注入等更清潔。但是,文件系統過濾器並不容易。

OSR Online是找到Windows文件系統信息的最佳位置。 NTFSD郵件列表是文件系統開發者閒逛的地方。

0

打開名爲「NUL:」的文件進行書寫。它是可寫的,但數據被無聲丟棄。有點像/ dev/null的* nix名聲。

雖然你不能記憶它。內存映射意味着讀/寫訪問,而NUL是隻寫的。

0

我在猜測這個DLL不能採取流?它幾乎要簡單地問,但如果它可以使用它。

+0

這是一個我不擁有的DLL,我也沒有它的源代碼,它只有一個帶有路徑的loadfile api。所以我不能改變這一點。 – 2010-01-25 10:27:43

3

使用BoxedApp,不用擔心。

+2

酷應用程序!它甚至可以與虛擬註冊表一起使用! – 2011-12-08 19:49:38