I would like to use manifest to load c++ dll in sub directory of the exe directory. For example: the folder structure like below:
LoadApp depends on LoadDll, both are native c++ projects. LoadDll.dll is in the sub directory "sdk". Run LoadApp.exe, it says "Can not find the LoadDll.dll". I have embedded the sdk.manifest fie to LoadApp.exe, but seems it does not work. Here is content of sdk.manifest:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<file name="sdk\LoadDll.dll">
</file>
</assembly>
I know using LoadLibrary or SetDllDirectory or Environment path can resolve the dll loading problem. But I would like to know what is wrong with manifest solution? Is it able to use manifest file for native c++ projects?
Related
I'm trying to set automatically run/debug environmental variables for my project in Visual Studio.
I mean, is there any CMake or C++ code line to do this not needing to do it manually?
Here are the instructions how to do it manually (what I want to avoid).
Here there is an still unsolved question about how to do it with Cmake (seems not to be possible).
I also tried with setenv() and putenv() in different ways but it didn't work, because the main function doesn't even run until that line of code, before an error message shows up: "Some.dll was not found" and the program stops.
If your dll is one you are intending to use, this answer details how to quickly ensure it is found at runtime (putting the DLL alongside the executable)
If by 'automatic' you mean in code, you can set environment variables in code using _putenv as described in this answer similar to what you seem to be describing.
ostringstream classSize;
classSize << "classSize=" << howManyInClass;
_putenv(classSize.str().c_str());
The solution I found is base on this answer.
Steps for the solution:
Create a UserTemplate.vcxproj.user file next to the CMakeLists.txt file, with the next content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerEnvironment>PATH=..\Your\Path\to\Binaries;%PATH%".</LocalDebuggerEnvironment>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
Where ..\Your\Path\to\Binaries is the relative path to your binary
files (the two points at the beginning .. are optional, if you
want to go up in the relative directory path, you may want to use
them).
Add the next lines of code in the CMakeLists.txt file.
# Configure the template file
SET(USER_FILE main.vcxproj.user)
SET(OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${USER_FILE})
CONFIGURE_FILE(UserTemplate.vcxproj.user ${USER_FILE} #ONLY)
Where ProjectName is the name of the VS project where you want to define your PATH variable.
I have two questions regarding activation context API and SxS manifests. They look like very simple, but still I cannot find any good answer for them.
I have two dll libraries with filenames foo.dll and bar.dll, both with embedded manifests, foo depends on bar. Is there any way to assign these two with assemblyIdentity name other than their filename? For example if I want assembly identity of bar.dll to be CompanyName.Subsection.bar ? If I change it's identity like this - I get error while I try to load foo.dll "Dependent Assembly CompanyName.Subsection.bar,type="win32",version="0.1.2.3" could not be found". Of course if I specify name assembly identities as filenames (<assemblyIdentity name="bar") everything works, but is there a way to use these dotted names?
foo.dll
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="foo" version="0.1.2.3" type="win32"/>
<dependency>
<dependentAssembly>
<assemblyIdentity name="CompanyName.Subsection.bar" version="0.1.2.3" type="win32" />
</dependentAssembly>
</dependency>
<file name="foo.dll">
</file>
</assembly>
bar.dll
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="CompanyName.Subsection.bar" version="0.1.2.3" type="win32"/>
<file name="bar.dll">
</file>
</assembly>
It can be done if instead of embedding the manifest for bar.dll you place it in a separate folder together with the dll itself. I.e.:
foo.dll
CompanyName.Subsection.bar/
├── bar.dll
└── CompanyName.Subsection.bar.manifest
You still need to embed the first manifest into foo.dll. I'm confident that you can remove the following snippet from that manifest, because it's an embedded manifest and therefore needs not to specify what dlls belong to the assembly:
<file name="foo.dll">
</file>
The manifest for bar.dll is good, but be sure to name the folder and the manifest file exactly as specified in the assemblyIdentity element (see example folder structure above).
Also note, that you can diagnose problems related to loading SxS assemblies with the sxstrace command line tool. Step by step instructions:
Run sxstrace trace -logfile:mytrace.etl from a Visual Studio Command Line. The command will not return until you press ENTER. However, do not press ENTER yet.
Start the application that loads foo.dll to reproduce your issue
Then press ENTER in the Command Line window to stop sxstrace
You now have a file mytrace.etl, which is not human readable. Convert it to a readable format by running sxstrace parse -logfile:mytrace.etl -outfile:mytrace.txt. You get a file mytrace.txt which shows what happens, when you load foo.dll and where it fails to resolve some of its dependencies.
Problem: I'm writing unittests for a Setup program in c++. The Setup needs admin rights, but the unittests do not. On starting the tests, I get asked for starting the test/program as Administrator.
This started happening when I included the rc-file of the original project.
Edit: I was upgrading this project to VS2010, but still using vc60, so there is no manifest support. This might be related.
Generally, the resources contain a manifest, and a portion of the manifest states whether the program needs administrator access. Since this is a setup utility, it probably has a manifest requiring administrator access and your tests picked it up when it tried to share the resource file.
(Other people are talking about the heuristics used to guess whether a program needs administrator access when it doesn't have a manifest. For example, if you have an old program that was made before manifest files were common, the OS might try to guess whether it's an installer by looking for certain phrases like "setup" in the file name. I believe there are other heuristics as well. This is a hack for older programs that were written before manifests made it possible to explicitly declare your need for administrator access.)
You can fix your problem by providing your own manifest. The easiest way is to use the /MANIFESTUAC linker option.
If you're using an older toolchain, you'll probably have to make the manifest file yourself and include it in your resources.
The manifest is a chunk of XML. The important bit for you would look something like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="yourprogram.exe" type="win32"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
To embed this in your resources, your .RC file should have:
1 RT_MANIFEST <filename>
If your SDK is so old that RT_MANIFEST is not defined, you can define it yourself:
#define RT_MANIFEST 24
One criteria for evaluating the needed rights for an application is the name.
So if the name contains the Word "Setup", you will be asked for admin rights.
Also, as this started with the rc file, another criteria are the names written in the rc-File, under "Version". In my case in "VS_VERSION_INFO".
The following entries are should not contain the word Setup:
FileDescription
InternalName
OriginalFilename
ProductName
You might change any occurance of "Setup" to "Settup". That would prevent the dialog.
Even though, you might not be able to change this in the "real" rc-file.
I want to do exactly what it is described here, but the accepted solution does not work for me. I suppose the reason is explained here :
If a DLL with dependencies is loaded
by specifying a full path, the system
searches for the DLL's dependent DLLs
as if they were loaded with just their
module names.
If a DLL with the same module name is
already loaded in memory, the system
checks only for redirection and a
manifest before resolving to the
loaded DLL, no matter which directory
it is in. The system does not search
for the DLL.
I wish to have my application in the following structure.
c:\Exe
|
|----- c:\DLL\DLL.dll, c:\DLL\common.dll
|
|----- c:\DLL2\DLL2.dll, c:\DLL2\common.dll
My EXE will load the DLLs through
LoadLibrary("c:\\DLL\\DLL.dll");
LoadLibraryEx("c:\\DLL2\\DLL2.dll");
common is implicitly loaded in both cases.
I tried the SetDllDirectory option, but there is always only one common.dll loaded.
I added version information in common.dll. c:\DLL\common.dll has version 2.0.1.0 while c:\DLL2\DLL2.dll has version 4.0.1.0
I embedded the following manifest with the corresponding version info, but it did not help.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="common" version="4.0.1.0" processorArchitecture="x86"></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
Is there a solution to this problem ?
Where have you embedded the manifest? The EXE or the DLLs?
You have two basic ways of doing this, both involve turning "common" into a private SxS assembly by creating a manifest for it.
Then:
If DLL and DLL2 contain manifests listing dependent assemblies, then you need to add a dependentAssembly to their manifests specifying "acme.common" (for example) as a dependent assembly. As dependent assemblies are always searched for, by default, in the loading modules folder, each DLL will load its own local copy of common.
If you are just relying on the applications default activation context to do most of the heavy lifting, then you can try using the ActivationContext API.
Call CreateActCtx twice, specifying two the two different folders as the base folder for the resulting context.
In pseudo code:
HACTCTX h1 = CreateActCtx( ... for DLL ... );
HACTCTX h2 = CreateActCtx( ... for DLL2 ...);
ActivateActCtx(h1,...);
LoadLibrary("C:\\DLL\\DLL1.DLL");
DeactivateActCtx();
ActivateActCtx(h2,...);
LoadLibrary("C:\\DLL2\\DLL2.DLL");
DeactivateActCtx...
If the dlls already contain their own manifests the system will use those. If not, this will let you specify a search directory for private assemblies without modifying the dll's themselves.
To implement Option 1:
First, I don't recommend trying to use the dll name as the assembly name. So, create a manifest that looks like this in each folder:
<!-- acme.common.manifest -->
<assembly manifestVersion="1.0">
<assemblyIdentity type="Win32" name="acme.common" version="1.0.0.0" processorArchitecture="x86"/>
<file name="common.dll"/>
</assembly>
You can fix the version number to match common.dll's version in each folder, but thats not important.
Then, either the manifest you list, or a directive like this if you are using Visual Studio
#pragma comment(linker, "/manifestdependency:\"acme.common'"\
" processorArchitecture='*' version='1.0.0.0' type='win32'\"")
Just make sure the dependent assembly versions match the versions of the corresponding 'acme.common' assembly.
I've read about the use of "Custom.Before.Microsoft.Common.targets" and "Custom.After.Microsoft.Common.targets" in order to execute a custom target before/after every project build and I would like to use this technique in order to change version info while building on our TeamCity build server.
The problem is that although it works for C# projects, it doesn't seem to work for native C++ projects.
After some digging around in the Microsoft.Cpp.targets file I found out that for native C++ projects this seems to be implemented through setting $(ForceImportBeforeCppTargets) and $(ForceImportAfterCppTargets).
I can't seem to find a single piece of information on the web about this technique for native C++ apps though, so I'm asking if I'm looking in the right direction or not.
Any help is appreciated.
For VC++ projects it is a bit different. You define a file to be imported either at the beginning or at the end of the project. To use this approach you need to define values for the properties ForceImportBeforeCppTargets or ForceImportAfterCppTargets. For example if you want a file to be included at the beginning of the project you can pass in the value at the command line. For example I just created a dummy VC++ project named CppTets01. Then I created the two sample files below.
Before.proj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CustomTargetInBefore" AfterTargets="Build">
<Message Text="From CustomTargetInBefore" Importance="high"/>
</Target>
</Project>
After.proj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CustomTargetInAfter" AfterTargets="Build">
<Message Text="From CustomTargetInAfter" Importance="high"/>
</Target>
</Project>
Then I executed the following command:
msbuild CppTest01.vcxproj
/p:ForceImportBeforeCppTargets="C:\Temp\_NET\ThrowAway\CppTest01\CppTest01\Before.proj";
ForceImportAfterCppTargets="C:\Temp\_NET\ThrowAway\CppTest01\CppTest01\After.proj"
The result was
C:\Temp_NET\ThrowAway\CppTest01\CppTest01>msbuild CppTest01.vcxproj /p:ForceImportBeforeCppTargets="C:\Temp_NET\ThrowAway\CppTest01\C
ppTest01\Before.proj";ForceImportAfterCppTargets="C:\Temp_NET\ThrowAway\CppTest01\CppTest01\After.proj"
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.1]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 10/18/2010 8:32:55 AM.
Project "C:\Temp\_NET\ThrowAway\CppTest01\CppTest01\CppTest01.vcxproj" on node 1 (default targets).
InitializeBuildStatus:
Creating "Debug\CppTest01.unsuccessfulbuild" because "AlwaysCreate" was specified.
ClCompile:
All outputs are up-to-date.
All outputs are up-to-date.
ManifestResourceCompile:
All outputs are up-to-date.
Link:
All outputs are up-to-date.
Manifest:
All outputs are up-to-date.
FinalizeBuildStatus:
Deleting file "Debug\CppTest01.unsuccessfulbuild".
Touching "Debug\CppTest01.lastbuildstate".
CustomTargetInBefore:
From CustomTargetInBefore
CustomTargetInAfter:
From CustomTargetInAfter
Done Building Project "C:\Temp\_NET\ThrowAway\CppTest01\CppTest01\CppTest01.vcxproj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.21
As you can see from the output the targets were successfully injected into the build process. If you want to relate this back to Custom.Before.Microsoft.Common.targets and Custom.Before.Microsoft.Common.targets then you should know that the technique used there is a bit different. Specifically if you create those files they are automatically imported into every C#/VB.NET project. In this case you have to set this property. You really have two options here:
You can set this property as an environment variable
You can use another technique, ImportBefore & ImportAfter which is specific to VC++
For #1 let me explain a bit. In MSBuild when you access a property with the syntax $(PropName) then if a property with the name PropName doesn't exist MSBuild will look up in the environment variables to see if such a value exists, if it does then that value is returned. So if you have a build server in which you want to include a file for each VC++ build, then just create those properties as environment variables. Now for the other technique.
ImportBefore/ImportAfter
In VC++ a new concept is introduced. In Microsoft.Cpp.Win32.targets you can see the declaration at the top of the .targets file.
<Import Project="$(VCTargetsPath)\Platforms\Win32\ImportBefore\*.targets"
Condition="Exists('$(VCTargetsPath)\Platforms\Win32\ImportBefore')" />
Then there is one towards the bottom
<Import Project="$(VCTargetsPath)\Platforms\Win32\ImportAfter\*.targets"
Condition="Exists('$(VCTargetsPath)\Platforms\Win32\ImportAfter')" />
A similar import declaration exists for the other target platforms as well. Take a look at the files at %ProgramFiles32%\MSBuild\Microsoft.Cpp\v4.0\Platforms\ for the specific names.
With this technique if you want a file to be imported then simply create a file that ends with .targets and place it into the appropriate folder. The advantage of this is that it will be imported into every VC++ build for that platform, and that you can create many different files. The drawback is that you have to place them in those specific folders. That's the main difference between both techniques. With this first technique you can specify the file location via property and its not automatically included for every build, but for the second approach it is but you cannot change the location
You can also add project content into one of *.props files from directory %LOCALAPPDATA%\Microsoft\MSBuild\v4.0\
It make same effect.