A worked example of using manifests to create side-by-side assembles to allow a single process to use two disparate versions of the same DLL.
Main application executable::
- MyApp.c:
#include <windows.h>
#include <stdio.h>
typedef void (WINAPI *BOOT)(void);
void __declspec(dllimport) doIt( void );
int main( int argc, char **argv ) {
char line[1024];
HMODULE ext;
BOOT boot;
doIt();
if( !( ext = LoadLibrary( argv[1] ) ) ) {
printf( "Failed to load library %s: error: %d\n",
argv[1], GetLastError()
);
exit( -1 );
}
if( !( boot = (BOOT)GetProcAddress( ext, "boot" ) ) ) {
printf( "Failed to get proc address for boot; error: %
+d\n",
GetLastError()
);
exit( -2 );
}
boot();
gets( line );
return 0;
}
MyApp.exe.manifest:
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.
+0'>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level='asInvoker' uiAccess='false' />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
- MyDll.c::
#include <stdio.h>
int __declspec(dllimport) depFunc( int, double );
void __declspec(dllexport) doIt( void ) {
printf( "MyDLL: depFunc return %d\n",
depFunc( 42, 3.141592653 )
);
return;
}
Mydll.dll.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="MyDll" version="1.0.0.0" proces
+sorArchitecture="amd64"/>
<file name="MyDll.dll" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Dep" version="2.0.0.0" proc
+essorArchitecture="amd64"/>
</dependentAssembly>
</dependency>
</assembly>
- Dep.c:
#include <stdio.h>
int __declspec(dllexport) depFunc( int a, double b ) {
printf( "depFunc: called with %d, %f\n", a, b );
return 1;
}
Dep.dll.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="Dep" version="2.0.0.0" processo
+rArchitecture="amd64"/>
<file name="Dep.dll" />
</assembly>
Extension dll:
- Ext\ExtDll.c:
#include <stdio.h>
int __declspec(dllimport) depFunc( int, int );
void __declspec(dllexport) boot() {
printf( "ExtDll: depFunc returned: %d\n ",
depFunc( 12345, 98765 )
);
return;
}
Ext\ExtDll.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="ExtDll" version="1.0.0.0" />
<file name="ExtDll.dll" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Dep" version="1.0.0.0" proc
+essorArchitecture="amd64"/>
</dependentAssembly>
</dependency>
</assembly>
- Ext\Dep.c:
#include <stdio.h>
int __declspec(dllexport) depFunc( int a, int b ) {
printf( "depFunc: called with %d, %d\n", a, b );
return 1;
}
ext\Dep.dll.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="Dep" version="1.0.0.0" processo
+rArchitecture="amd64"/>
<file name="Dep.dll" />
</assembly>
Build:
C:\test\myApp\Ext>cl /nologo /LD Dep.c
Dep.c
Creating library Dep.lib and object Dep.exp
C:\test\myApp\Ext>mt /nologo -manifest Dep.dll.manifest -outputresourc
+e:Dep.dll;2
C:\test\myApp\Ext>cl /nologo /LD ExtDll.c Dep.lib
ExtDll.c
Creating library ExtDll.lib and object ExtDll.exp
C:\test\myApp\Ext>mt /nologo -manifest ExtDll.dll.manifest -outputreso
+urce:ExtDll.dll;2
C:\test\myApp\Ext>cd ..
C:\test\myApp>cl /nologo /LD Dep.c
Dep.c
Creating library Dep.lib and object Dep.exp
C:\test\myApp>mt /nologo -manifest Dep.dll.manifest -outputresource:De
+p.dll;2
C:\test\myApp>cl /nologo /LD myDll.c Dep.lib
myDll.c
Creating library myDll.lib and object myDll.exp
C:\test\myApp>mt /nologo -manifest MyDll.dll.manifest -outputresource:
+MyDll.dll;2
C:\test\myApp>cl /nologo myApp.c MyDll.lib
myApp.c
C:\test\myApp>mt /nologo -manifest MyApp.exe.manifest -outputresource:
+MyApp.Exe;1
And a run:
C:\test\myApp>MyApp.Exe Ext\ExtDll.dll
depFunc: called with 42, 3.141593
MyDLL: depFunc return 1
depFunc: called with 12345, 98765
ExtDll: depFunc returned: 1
And there you have it. One executable using two different versions of the same (named) dll without conflict.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
RIP Neil Armstrong