2008-11-29 30 views
8

Tôi đang thiếu bộ não của mình đang cố gắng đưa ra giải pháp thanh lịch cho vấn đề tải DLL. Tôi có một ứng dụng tĩnh liên kết đến các tập tin lib khác mà tải DLL. Tôi không tải trực tiếp các tệp DLL. Tôi muốn có một số DLL trong một thư mục khác ngoài thư mục mà tệp thực thi đang ở. Thứ gì đó giống như% working_folder% \ dlls - Tôi không muốn có hàng tá (có ... hàng chục) tệp DLL trong% working_folder% của mình .thêm đường dẫn tìm kiếm DLL tùy chỉnh @ khởi động ứng dụng

Tôi đang cố gắng phát triển thứ gì đó là một phần của ứng dụng chính sẽ điều chỉnh đường dẫn tìm kiếm @ startup. Vấn đề tôi đang gặp phải là đường dẫn DLL tùy chỉnh mới này không nằm trong đường dẫn tìm kiếm hệ thống. Khi tôi bắt đầu ứng dụng nó treo (STATUS_DLL_NOT_FOUND) bởi vì các DLL cần thiết không phải là ở những nơi thích hợp. Những gì tôi muốn làm là để kiểm tra @ khởi động nếu thư mục DLL tùy chỉnh mới này là trong quá trình tìm kiếm biến môi trường đường dẫn và nếu không thêm nó. Vấn đề là, ứng dụng sẽ cố tải tất cả các tệp DLL này trước khi ứng dụng thực hiện một dòng mã.

Làm cách nào để khắc phục sự cố này? Tôi đã xem xét việc viết một ứng dụng trợ giúp bắt đầu trước, điều chỉnh các biến môi trường một cách thích hợp và khởi chạy ứng dụng chính thông qua CreateProcess. Điều này sẽ làm việc tôi chắc chắn về nó nhưng nó làm cho mọi thứ khó khăn trên các nhà phát triển. Khi họ gỡ lỗi ứng dụng chính, họ sẽ không khởi chạy ứng dụng trợ giúp đầu tiên - không phải là họ thậm chí có thể làm điều đó.

Tôi đã thử tính năng đường dẫn ứng dụng đăng ký không thành công. Cùng một vấn đề về gà và trứng như trước.

Tôi có thể làm gì ở đây?

Trả lời

2

[Edit - sau khi đọc lại những câu hỏi tôi thấy rằng vấn đề bạn đang gặp phải là các DLL đang nhận được nạp trước khi bắt đầu main]

Tôi đoán rằng những thư viện được viết bằng C++ và tải các DLL từ constructor của một số đối tượng trong phạm vi toàn cục. Đây là vấn đề. Cho phép tôi báo giá Yossi Kreinin:

Thực hiện điều đầu tiên trong main(). Nếu bạn sử dụng C++, bạn nên làm điều đầu tiên trước khi main(), bởi vì mọi người có thể sử dụng FP trong các hàm tạo của các biến toàn cầu. Điều này có thể đạt được bằng cách tìm ra trình tự khởi tạo đơn vị dịch thuật cụ thể, biên dịch thư viện khởi động C/C++ của riêng bạn, ghi đè điểm vào của thư viện khởi động được biên dịch bằng các công cụ như LD_PRELOAD, ghi đè nó trong chương trình liên kết tĩnh ngay trong hình ảnh nhị phân, có quy ước mã hóa buộc gọi FloatingPointSingleton :: instance() trước khi sử dụng FP hoặc chụp những người thích làm việc trước main(). Đó là một sự cân bằng.

[câu trả lời dưới đây Original]

Xem this page cho các thuật toán tìm kiếm được sử dụng để tải các file DLL. Bạn có thể sử dụng SetDllDirectory() để thêm một thư mục vào đường dẫn tìm kiếm DLL.

Bạn cũng có thể thêm thư mục vào biến môi trường PATH sử dụng GetEnvironmentVariable()SetEnvironmentVariable().

Một tùy chọn khác là thay đổi thư mục làm việc hiện tại thành thư mục chứa các tệp DLL với SetCurrentDirectory(). Chỉ cần chắc chắn để thay đổi thư mục làm việc trở lại sau khi tải các DLL nếu bạn đã bao giờ tải bất kỳ tập tin bằng cách sử dụng tên tập tin tương đối.

+0

Liệu Windows có cái gì đó như @load_path trong OS X? Cụ thể để xác định đường dẫn tìm kiếm liên quan đến DLL hiện tại hoặc một cái gì đó? Cảm ơn bạn. – Royi

2

Đề xuất của tôi là sử dụng tải trễ liên kết cho các tệp DLL và gọi SetDllDirectory() đủ sớm để có thể tìm thấy chúng khi các phương thức/hàm được gọi.

+2

Lưu ý: có rất nhiều điều bạn không thể làm trong DllMain, chẳng hạn như tải giá trị đăng ký. Nhưng gọi SetDllDirectory ("./ dll_dir") * có thể * hoạt động. Không được kiểm tra. –

3

Tôi tìm thấy câu trả lời của Matthew đã làm việc cho tôi.

Trong studio trực quan 2012 goto thuộc tính dự án của bạn và trong Thuộc tính cấu hình-> Linker-> Input-> Delay Loaded Dlls thêm mỗi tệp dll mà bạn không muốn tải cho đến khi cần thiết.

Mặc dù nó không còn cần phải chạy trước khi chính, đây là mã của tôi để thiết lập các đường dẫn tìm kiếm mới

class RunBeforeMain 
{ 
public: 
    RunBeforeMain() 
    { 
     const TCHAR* dllPathEnvName= name of env variable to directory containing dlls 
     const TCHAR* pathEnvName= TEXT("Path"); 


     TCHAR newSearchPath[4096]; 
     ::GetEnvironmentVariable(dllPathEnvName, newSearchPath, MAX_PATH); 

      //append bin 
     _tcscat_s(newSearchPath, MAX_PATH, TEXT("bin;")); 
     size_t length = _tcslen(newSearchPath); 

      //append existing Path 
     ::GetEnvironmentVariable(pathEnvName, newSearchPath + length, 4096-length); 
     ::SetEnvironmentVariable(pathEnvName, newSearchPath); 

    } 
}; 
static RunBeforeMain runBeforeMain; //constructor code will run before main. 
Các vấn đề liên quan