none
How to write manifest file to pick up dlls via dll redirection

    Question

  • Hi,


    I need a help for following problem:

    I have set of applications organized in some directory structure say

    C:/Product/A/bin/python26.dll
    C:/Product/A/bin/zlib.dll

    C:/Product/B/bin/program_1.exe <dependent on python26.dll and zlib.dll>
    C:/Product/C/bin/program_2.exe <dependent on python26.dll and zlib.dll>

    Sometimes, these python26.dll and zlib.dll are found in C:/WinNt/system32 directory for some reason, so our dlls are not picked up even we have C:/Product/A/bin/ directory in the PATH environment.

    Reason behind this is the Windows dll search order (which first search in the same directory where application resides, followed by System folders, and then PATH environment variable).


    Is there a way to write an application manifest file which can instruct that dll should be picked up from C:/Product/A/bin directory before looking into System folders?

    If yes, then what should be the content of manifest file for above situation for example?


    Any help would be appreciated in this regard?


    -Vipin
    Wednesday, July 28, 2010 4:42 PM

Answers

  • Step 1 would be to take each of your dll's, and turn them into an assembly. Or assemblies.

     

    You do this - simply, by adding a .manifest file to the same folder as the dll. In this case: python.assembly.manifest

     

       

    <assembly manifestVersion="1.0">
      <assemblyIdentity type="Win32" name="python.assembly" version="1.0.0.0" processorArchitecture="x86" publicKeyToken="257fa66c876581b9"/>
     <file name="python26.dll" hashalg="SHA1"/>
    </assembly> 
    
    
    

    you could all all the dll's to a single assembly just by listing multiple <file> nodes. The public key token is really just a random number. As its not actually used for signing anything in a private SxS deployment, its not necessary. You could probably leave it out entirely actually.

    Step 2 - make the applications use the assemblies to load the dlls.

    Assuming you are using Devstudio 2005 or 2008, simply add the following code to a (not managed) cpp, c or header file:

    #pragma comment(linker,"/manifestdependency:\"type='win32' "\
      "name='python.assembly' "\
      "version='1.0.0.0' "\
      "processorArchitecture='*' "\
      "language='*' "\
      "\"") 
    
    Step 3 - test that the manifests are all correct. Copy everything into the same folder and execute the .exe - Well, copy the assemblies into a sub folder for now so we can be sure theyre working:

    c:/Product/B/bin/program_1.exe
    c:/Product/B/bin/python.assembly/python.assembly.manifest
    c:/Product/B/bin/python.assembly/python26.dll

    If it says something about the application could not be started due to problems in the activation context, something is not matching up properly. If it loads, its because it found the assembly "python.assembly" when loading the exe file, parsed it, and found the python26.dll in the assembly.

    Step 4. Add an application configuration file to do a probing path: this file will be: (The contents of this file cannot be stored in the EXE as a resource like the manifest.)

    c:/Product/B/bin/program_1.exe.config

    <configuration>
     <windows>
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
     <probing privatePath="../../A/bin"/>
     </assemblyBinding>
     </windows>
    </configuration>
    
    
    Move the (working) assemblies to the specified relative path.

    c:/Project/A/bin/python.assembly.manifest
    c:/Project/A/bin/python26.dll

    is valid. So is

    c:/Project/A/bin/python.assembly/python.assembly.manifest
    c:/Project/A/bin/python.assembly/python26.dll

    Support for the probing privatePath element was only added with Windows Server 2008 and Windows 7, so you cannot use this method to target Windows Vista. With Windows Vista the only shared location that will be searched for assemblies is WinSxS - so you would need to create a strongly named assembly and install it using a .MSI

    This URL has more information (on application configuration files specifically)

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

    • Edited by Farproc Wednesday, July 28, 2010 8:03 PM fixed some typos. additional info
    • Marked as answer by Vipin Jain Thursday, July 29, 2010 10:20 AM
    Wednesday, July 28, 2010 7:56 PM
  • Thanks, I got your point.

    <!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-alt:"Calisto MT"; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-alt:"Times New Roman"; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:Consolas; panose-1:2 11 6 9 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:modern; mso-font-pitch:fixed; mso-font-signature:-1610611985 1073750091 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} p.MsoPlainText, li.MsoPlainText, div.MsoPlainText {mso-style-noshow:yes; mso-style-priority:99; mso-style-link:"Plain Text Char"; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.5pt; font-family:Consolas; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} span.PlainTextChar {mso-style-name:"Plain Text Char"; mso-style-noshow:yes; mso-style-priority:99; mso-style-unhide:no; mso-style-locked:yes; mso-style-link:"Plain Text"; mso-ansi-font-size:10.5pt; mso-bidi-font-size:10.5pt; font-family:Consolas; mso-ascii-font-family:Consolas; mso-hansi-font-family:Consolas;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} @page WordSection1 {size:8.5in 11.0in; margin:1.0in 1.0in 1.0in 1.0in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.WordSection1 {page:WordSection1;} -->

    We are thinking other alternative like create hardlink to each DLL in each product's bin directory. This will help to address platforms starting from WinXP.

     

    Do you think it is a reasonable approach?

     

    <!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-alt:"Calisto MT"; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-alt:"Times New Roman"; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:Consolas; panose-1:2 11 6 9 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:modern; mso-font-pitch:fixed; mso-font-signature:-1610611985 1073750091 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} p.MsoPlainText, li.MsoPlainText, div.MsoPlainText {mso-style-noshow:yes; mso-style-priority:99; mso-style-link:"Plain Text Char"; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.5pt; font-family:Consolas; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} span.PlainTextChar {mso-style-name:"Plain Text Char"; mso-style-noshow:yes; mso-style-priority:99; mso-style-unhide:no; mso-style-locked:yes; mso-style-link:"Plain Text"; mso-ansi-font-size:10.5pt; mso-bidi-font-size:10.5pt; font-family:Consolas; mso-ascii-font-family:Consolas; mso-hansi-font-family:Consolas;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} @page WordSection1 {size:8.5in 11.0in; margin:1.0in 1.0in 1.0in 1.0in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.WordSection1 {page:WordSection1;} --> 

    E.g.

    Actual file : C:/Product/A/bin/test.dll

    Hard link to C:/A/test.dll from another directory: C:/Product/B/bin/test.dll

    If I check the size of C:/Product folder from explorer or Dir command, it show double of actual size.

     

    Any idea how can I verify the actual size consumed by C:\Product folder after creating hard-link?

     

     

     

     

     

    • Marked as answer by Vipin Jain Thursday, July 29, 2010 10:19 AM
    Thursday, July 29, 2010 8:31 AM

All replies

  • Step 1 would be to take each of your dll's, and turn them into an assembly. Or assemblies.

     

    You do this - simply, by adding a .manifest file to the same folder as the dll. In this case: python.assembly.manifest

     

       

    <assembly manifestVersion="1.0">
      <assemblyIdentity type="Win32" name="python.assembly" version="1.0.0.0" processorArchitecture="x86" publicKeyToken="257fa66c876581b9"/>
     <file name="python26.dll" hashalg="SHA1"/>
    </assembly> 
    
    
    

    you could all all the dll's to a single assembly just by listing multiple <file> nodes. The public key token is really just a random number. As its not actually used for signing anything in a private SxS deployment, its not necessary. You could probably leave it out entirely actually.

    Step 2 - make the applications use the assemblies to load the dlls.

    Assuming you are using Devstudio 2005 or 2008, simply add the following code to a (not managed) cpp, c or header file:

    #pragma comment(linker,"/manifestdependency:\"type='win32' "\
      "name='python.assembly' "\
      "version='1.0.0.0' "\
      "processorArchitecture='*' "\
      "language='*' "\
      "\"") 
    
    Step 3 - test that the manifests are all correct. Copy everything into the same folder and execute the .exe - Well, copy the assemblies into a sub folder for now so we can be sure theyre working:

    c:/Product/B/bin/program_1.exe
    c:/Product/B/bin/python.assembly/python.assembly.manifest
    c:/Product/B/bin/python.assembly/python26.dll

    If it says something about the application could not be started due to problems in the activation context, something is not matching up properly. If it loads, its because it found the assembly "python.assembly" when loading the exe file, parsed it, and found the python26.dll in the assembly.

    Step 4. Add an application configuration file to do a probing path: this file will be: (The contents of this file cannot be stored in the EXE as a resource like the manifest.)

    c:/Product/B/bin/program_1.exe.config

    <configuration>
     <windows>
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
     <probing privatePath="../../A/bin"/>
     </assemblyBinding>
     </windows>
    </configuration>
    
    
    Move the (working) assemblies to the specified relative path.

    c:/Project/A/bin/python.assembly.manifest
    c:/Project/A/bin/python26.dll

    is valid. So is

    c:/Project/A/bin/python.assembly/python.assembly.manifest
    c:/Project/A/bin/python.assembly/python26.dll

    Support for the probing privatePath element was only added with Windows Server 2008 and Windows 7, so you cannot use this method to target Windows Vista. With Windows Vista the only shared location that will be searched for assemblies is WinSxS - so you would need to create a strongly named assembly and install it using a .MSI

    This URL has more information (on application configuration files specifically)

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

    • Edited by Farproc Wednesday, July 28, 2010 8:03 PM fixed some typos. additional info
    • Marked as answer by Vipin Jain Thursday, July 29, 2010 10:20 AM
    Wednesday, July 28, 2010 7:56 PM
  •  

    Thanks for sharing this idea.  It looks promising, I need to try though.

    - Does it work for XP too?

     

    Thanks,

    Vipin

    Thursday, July 29, 2010 3:10 AM
  • Not at all. Not even on Vista.

    Windows 2008 Server and Windows 7 added support for the <probing privatePath> element.

    With 2008 and Win7 the only places assemblies are searched for are in the EXE's own folder, and in WinSxS.

    You already know the dll search path for dll's outside assemblies - and its just not (as you have found) reliable. There are of course tricks you can play with LoadLibraryEx and passing the altered search path flag - or using the necessary switches to delay load the dll's and ensure that SetDllSearchDirectory is called before the first exported API if you really need this kind of functionality on XP.

    Thursday, July 29, 2010 5:44 AM
  • Thanks, I got your point.

    <!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-alt:"Calisto MT"; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-alt:"Times New Roman"; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:Consolas; panose-1:2 11 6 9 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:modern; mso-font-pitch:fixed; mso-font-signature:-1610611985 1073750091 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} p.MsoPlainText, li.MsoPlainText, div.MsoPlainText {mso-style-noshow:yes; mso-style-priority:99; mso-style-link:"Plain Text Char"; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.5pt; font-family:Consolas; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} span.PlainTextChar {mso-style-name:"Plain Text Char"; mso-style-noshow:yes; mso-style-priority:99; mso-style-unhide:no; mso-style-locked:yes; mso-style-link:"Plain Text"; mso-ansi-font-size:10.5pt; mso-bidi-font-size:10.5pt; font-family:Consolas; mso-ascii-font-family:Consolas; mso-hansi-font-family:Consolas;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} @page WordSection1 {size:8.5in 11.0in; margin:1.0in 1.0in 1.0in 1.0in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.WordSection1 {page:WordSection1;} -->

    We are thinking other alternative like create hardlink to each DLL in each product's bin directory. This will help to address platforms starting from WinXP.

     

    Do you think it is a reasonable approach?

     

    <!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-alt:"Calisto MT"; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-alt:"Times New Roman"; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:Consolas; panose-1:2 11 6 9 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:modern; mso-font-pitch:fixed; mso-font-signature:-1610611985 1073750091 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} p.MsoPlainText, li.MsoPlainText, div.MsoPlainText {mso-style-noshow:yes; mso-style-priority:99; mso-style-link:"Plain Text Char"; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.5pt; font-family:Consolas; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} span.PlainTextChar {mso-style-name:"Plain Text Char"; mso-style-noshow:yes; mso-style-priority:99; mso-style-unhide:no; mso-style-locked:yes; mso-style-link:"Plain Text"; mso-ansi-font-size:10.5pt; mso-bidi-font-size:10.5pt; font-family:Consolas; mso-ascii-font-family:Consolas; mso-hansi-font-family:Consolas;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} @page WordSection1 {size:8.5in 11.0in; margin:1.0in 1.0in 1.0in 1.0in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.WordSection1 {page:WordSection1;} --> 

    E.g.

    Actual file : C:/Product/A/bin/test.dll

    Hard link to C:/A/test.dll from another directory: C:/Product/B/bin/test.dll

    If I check the size of C:/Product folder from explorer or Dir command, it show double of actual size.

     

    Any idea how can I verify the actual size consumed by C:\Product folder after creating hard-link?

     

     

     

     

     

    • Marked as answer by Vipin Jain Thursday, July 29, 2010 10:19 AM
    Thursday, July 29, 2010 8:31 AM
  • Explorer will always count the size of all the files.

    The simplest way to prove that the hardlinks dont occupy extra space would be to count the _free_ space on the volume before and after hardlink creation.

     

    Thursday, July 29, 2010 8:51 AM
  • Yes, it is useful. I created 1000 hard-links where my dll size was 85k, but there is no disk space increase. If it really increases then it should have shoot up by 85k*1000.

    Thursday, July 29, 2010 9:37 AM