2010-09-30 39 views
11

Tôi đã tìm kiếm bất kỳ gợi ý nào về cách thực hiện điều này, nhưng tất cả những gì tôi tìm thấy là cách chuyển hướng tệp SxS DLL sang thư mục ứng dụng cục bộ. Đây là những gì tôi muốn thực hiện: (C++) Application.exe được liên kết với một DLL, Plugin.DLL (dự án phụ thuộc). DLL này không được đặt bên trong thư mục ứng dụng, nhưng trong một thư mục con được gọi là "plugins". Khi DLL được liên kết tĩnh, ứng dụng sẽ cố gắng tải nó từ thư mục ứng dụng.Thay đổi đường dẫn tìm kiếm DLL cho DLL được liên kết tĩnh

Có cách nào để tôi có thể thay đổi đường dẫn tìm kiếm cho DLL cụ thể này không? Hoặc thông qua biểu hiện hoặc cấu hình liên kết VS2008?

Trả lời

17

Suy nghĩ đầu tiên của tôi là, nếu bạn liên kết tĩnh một dll, nó không phải là một plugin. Chỉ cần đặt dll trong thư mục EXE và được thực hiện với nó. Đó là cấu hình triển khai được hỗ trợ bởi các cửa sổ cho các DLL được tải tĩnh.

Điều đó nói rằng, có nhiều cách để đạt được những gì bạn muốn. Nhưng chúng chủ yếu là ngu ngốc, hoặc phức tạp không có lý do chính đáng: Các tùy chọn của bạn là:

  • Không liên kết tĩnh. Sử dụng LoadLibrary ("plugins/Plugin.dll") & GetProcAddress để truy cập nội dung plugin.
  • Thêm "đường dẫn tới thư mục plugin của bạn" vào biến môi trường PATH của hệ thống.
  • Sử dụng cơ chế tải chậm trễ để trì hoãn việc truy cập chức năng bổ trợ, đặt custom helper function có thể tải (các) dll bằng cách sử dụng đường dẫn được cung cấp.
  • Bật thư mục plugin thành một hội đồng (bằng cách tạo tệp .manifest trong đó liệt kê plugin.dll). Thêm "plugins" làm một hội đồng phụ thuộc vào ứng dụng của bạn. Bây giờ nó sẽ tìm trong thư mục plugins.
  • Chia ứng dụng của bạn thành một exe sơ khai và phần được nạp động. Trong exe exe gọi SetDllDirectory để trỏ đến thư mục plugin, sau đó gọi LoadLibrary đi qua đường dẫn đầy đủ đến "appstub.dll".

Để bật một thư mục, với một hoặc nhiều của dll thành một "lắp ráp", chỉ cần thêm một tập tin vào thư mục với các thư mục name.manifest.

Vì vậy, plugins.manifest: -

<assembly manifestVersion="1.0"> 
    <assemblyIdentity type="Win32" name="Plugins" version="1.0.0.0" processorArchitecture="x86" /> 
    <file name="Plugin.dll"/> 
</assembly> 

Đó là một ý tưởng rất tốt để đảm bảo rằng các thư mục và tên của dll là khác nhau, nếu như tên dll là cửa sổ tên lắp ráp bắt đầu nhìn vào nhúng nó tệp kê khai để biết thông tin về hội đồng.

Giả sử bạn đang sử dụng Visual Studio 7 trở lên, chỉ thị sau được thêm vào tệp .c/.cpp hoặc.h tập tin trong dự án sau đó sẽ làm cho nỗ lực ứng dụng của bạn để tải dlls từ lắp ráp chứ không phải chỉ là thư mục địa phương:

#pragma comment(linker, "/manifestdependency:\"name='Plugins' "\ 
         "processorArchitecture='*' version='1.0.0.0' "\ 
         "type='win32'\"") 
+0

Cảm ơn - Tôi đã tiếp cận phương pháp GetProcAddress vì tôi không thể hiểu được cách biểu hiện giống như cách làm cho phương pháp "lắp ráp giả" hoạt động. May mắn thay, điều này hoạt động tốt với kiến ​​trúc tổng thể. – Oliver

+1

Bạn không cần 'SetDllDirectory' để tải trễ; có một móc '__pfnDliNotifyHook2' để bạn có thể gọi trực tiếp' LoadLibrary (". \\ plugins \\ PluginX.dll") '. Ý tưởng '% PATH%' hơi mỏng manh vì nó khá thấp trong danh sách các vị trí cần kiểm tra. – MSalters

+0

cảm ơn. Tôi đã không bao giờ cá nhân sử dụng tải chậm trễ vì vậy tôi chỉ giả định rằng SetDllDirectory sẽ là cách để điều chỉnh nó. –

5

Mở rộng và detailing Chris' proposal của một "lắp ráp" thư mục con:


Side lưu ý : Chris cũng có hai ghi up tuyệt vời của biết thêm chi tiết:


MS docs

này là thực sự gọi là "Private Assembly" và MS tài liệu giải thích nó theo cách này:

Private bộ phận nhỏ được cài đặt trong một thư mục của cấu trúc thư mục của ứng dụng. Thông thường, đây là thư mục chứa tệp thực thi của ứng dụng . private assemblies có thể được triển khai trong thư mục tương tự như các ứng dụng, trong một thư mục với tên giống như lắp ráp, hoặc trong một thư mục con ngôn ngữ cụ thể với cùng tên như lắp ráp.

Ví dụ (...)

Appdir\Microsoft.Tools.Pop\Microsoft.Tools.Pop.MANIFEST: Các biểu hiện được triển khai như một tập tin riêng biệt trong một thư mục con có tên của assembly.

(...)

Private hội có thể được cài đặt bởi bất kỳ phương pháp cài đặt mà có thể sao chép tập tin của assembly vào thư mục này, chẳng hạn như lệnh xcopy.

Ví dụ

Bạn có bạn đáng tin cậy tuổi thực thi trong chương trình bạn thư mục C:\Test\Program\app.exe và bạn muốn - at Load-Time - tải tập tin DLL của bạn từ Plugins thư mục con, tức là C:\Test\Program\plugins\tool1.dllmà không rối tung với PATH hoặc bất kỳ nội dung nào khác.

Bạn cần phải:

  • Compile app.exe với:

    #pragma comment(linker, "/manifestdependency:\"name='Plugins' version='1.0.0.0' type='win32'\"") 
    // name, type and version seems to be the minimum info to get away with 
    

    Lưu ý: Biên dịch/Liên kết này trong, thay vì sử dụng một biểu hiện bên ngoài (app.exe.manifest) là bắt buộc trên hệ thống kiểm tra của tôi, tôi đã không tìm ra lý do tại sao.(* a)

    Điều gì cũng hoạt động tuy nhiên đang nhúng/hợp nhất tệp kê khai được liệt kê bên dưới vào tệp thực thi bằng công cụ mt, thay vì với pragma của trình liên kết. (Configuration > Manifest Tool > Additional Manifest Files)

  • đặt tool1.dll INTRO các plugins thư mục con

  • thêm một tập tin plugins.manifest vào các plugins thư mục con, tức là C:\Test\Program\plugins\plugins.manifest và rằng một trông như thế này:

plugins. manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <assemblyIdentity 
          type="win32" 
          name="Plugins" 
          version="1.0.0.0" 
      /> 
    <file name="tool1.dll"/> 
</assembly> 

Vậy đó. Khởi động app.exe sẽ tự động tìm dll trong thư mục con tại thời gian tải.


(* a): Kết hợp file manifest này làm việc, nhưng bạn không thể sử dụng như là file manifest bên ngoài duy nhất, và tôi nghi ngờ đó là vì nó còn thiếu tất cả các thông tin manifest khác xây dựng hệ thống đã đặt vào thực thi của bạn!

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <dependency> 
     <dependentAssembly> 
      <!-- Note: type: The value must be win32 and all in lower case. Required. --> 
      <!-- Note: version: The value must be win32 and all in lower case. Required. --> 
      <assemblyIdentity 
            type="win32" 
            name="plugins" 
            version="1.0.0.0" 
      /> 
     </dependentAssembly> 
    </dependency> 
</assembly> 
+0

Các wiki numpy @ https://github.com/numpy/numpy/wiki/windows-dll-notes cũng có một tốt đẹp viết lên này –

+0

Tệp kê khai bên ngoài chỉ được sử dụng Tôi nghĩ rằng nếu không có tệp kê khai được nhúng. Trình biên dịch VS hiện nhúng các tệp kê khai theo mặc định để tải thời gian biểu hiện chỉ có thể xảy ra nếu bạn loại bỏ tệp đó trước tiên. –

Các vấn đề liên quan