2011-08-24 21 views
1

我正在尋找一種方法來在同一個進程中協調DLL,以便在它們之間提供數據共享機制。目標是爲所有DLL提供相同的共享代碼,並讓它們以這樣一種方式進行協調,即主程序加載的第一個代碼將用作共享項目的管理器,而其他代碼將使用此管理器。我無法修改主應用程序,因此設置管理器並與其他DLL共享內存地址是不可能的。使用這種機制的DLL集可能會有所不同,所以我不能明確地假設它們中的一個將被加載。如何在沒有主機程序幫助的情況下協調同一進程中的各種DLL?

我考慮的一種解決方案是將內存地址添加到進程的環境變量中。第一個DLL會看到環境變量尚未設置,創建管理器對象並將該變量設置爲其地址。其他DLL會看到變量並從中創建一個指向管理器對象的指針。

這接近我想要的,但它似乎有點粗糙,因爲不能保證環境變量由於某種原因而未被設置,並且SetEnvironmentVariable/GetEnvironmentVariable可能由於各種原因而失敗。

有沒有更好的方法來處理這個問題?我正在尋找一種方法來存儲和檢索進程上下文中的指定指針,但是如果您有更好的解決方案來解決DLL合作的基本問題,我很樂意接受這一點。

回答

1

結合GetModuleHandle()GetProcAddress()來實現這一點。依賴的DLL將獲取管理器DLL的句柄,然後使用GetProcAddress()從其導出的符號檢索指針。

或者只是動態鏈接依賴的DLL對管理器DLL,並使用頭文件的extern定義。


我最初誤解了你的問題;但是,上述方法仍然有用。

您可以要求這些DLL都導出一個指向某個結構或函數的相同符號。然後,當其中一個庫被初始化時,它可以枚舉進程中加載​​的模塊並查找該符號。如果取消引用GetProcAddress()返回的指針返回一個空指針,那麼這個模塊是第一個加載的模塊,應該創建所需的結構並設置它自己的變量。否則,它使用從指針獲取的值。

儘管這種方法充滿了競爭條件,但這些模塊可以同時初始化。最好讓每個模塊都可以用作通信點的單個管理引擎模塊。

+0

我認爲這個,但我不想有一個專用的經理DLL。這些DLL是Game Maker的擴展,並且遵循你建議的路線,管理器DLL或者需要被包含在使用這個系統的每個擴展中,或者被想要使用擴展的程序員手動包含,並且我想以避免這種額外的依賴性。 – Medo42

+0

@cdhowie,模塊無法在Windows上同時初始化;加載程序鎖確保只有一個DLL的入口點可以在一個時間執行 – bdonlan

+2

@ Medo42:解決方案是讓每個DLL都提供自己的管理器?當你需要升級經理時會發生什麼?如果任何一個模塊實現了一個較舊的版本並首先被加載,那麼該進程將被迫使用較舊的版本。依賴可能很煩人,但是這種情況很快就會變成一個更糟糕的DLL版本,因爲哪個版本的管理器被加載可能是不可預知的。不要讓你的開發者接受這一點。對於正確的頭文件的強烈依賴會使您的生活(以及開發人員)從長遠來看變得更加輕鬆。 – cdhowie

2

如何創建named shared memory

這將允許您共享內存的一部分,而無需獲取在進程上下文中有效的地址的麻煩。第一個加載的DLL創建共享內存,然後下一個DLL可以直接訪問內存,您可以在此之上構建自己的消息傳遞API。

+0

並確保您使用互斥體等進行訪問,因爲您將擁有併發訪問權限。 +感謝@Adrien Plisson,你的鏈接幫助我解決了一個有點相關的問題。 – ixe013

+0

這通常會起作用,但由於命名共享內存是在進程之間共享的,所以我們需要特別小心,這是我明確不想要的。仍然贊成這個想法。 – Medo42

0

cdhowie提供了一些很好的理由,爲什麼這是一個壞主意。但是,如果您真的想這樣做,而不污染全局共享內存名稱空間:在您的DLL入口點註冊一個窗口類,但傳遞EXE的實例作爲窗口類的hInstance字段。

每個DLL都可以檢查該類是否已經註冊;如果沒有,請自行註冊。成功註冊窗口類的第一個DLL成爲主窗口。要獲取指向由後續加載的DLL中的主設備初始化的某個結構的指針,請創建該類的僅消息窗口,並使用SendMessage來調用其窗口過程(在主DLL中)。

相關問題