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.
Related
In a C++ console application on windows, i'm trying to break the MAX_PATH restriction for the SetCurrentDirectoryW function.
There are many similar questions already asked but none got a usable answer:
How to enable "Long Path Aware" behavior via manifest in a C++ executable?
Are long path behavior per app can be enable via the manifest?
Doc Research
Apparently this might be possible by using application manifest files. The docs for SetCurrentDirectoryW state:
Tip Starting with Windows 10, version 1607, for the unicode version
of this function (SetCurrentDirectoryW), you can opt-in to remove the
MAX_PATH limitation. See the "Maximum Path Length Limitation" section
of Naming Files, Paths, and Namespaces for details.
And from the general docs about Manifests:
Manifests are XML files that accompany and describe side-by-side
assemblies or isolated applications.
...
Application Manifests describe isolated applications. They are used to
manage the names and versions of shared side-by-side assemblies that
the application should bind to at run time. Application manifests are
copied into the same folder as the application executable file or
included as a resource in the application's executable file.
The docs about Assembly Manifests point out the difference to Application Manifests once more:
As a resource in a DLL, the assembly is available for the private use
of the DLL. An assembly manifest cannot be included as a resource in
an EXE. An EXE file may include an Application Manifests as a resource.
The docs about Application Manifests list the assembly and assemblyIdentity elements as required:
The assembly element requires exactly one attribute:
manifestVersion
The manifestVersion attribute must be set to 1.0.
The assemblyIdentity element requires the following attributes:
type
The value must be Win32 and all in lower case
name
Use the following format for the name: Organization.Division.Name. For example Microsoft.Windows.mysampleApp.
version
Specifies the application or assembly version. Use the four-part version format: mmmmm.nnnnn.ooooo.ppppp. Each of the parts separated by periods can be 0-65535 inclusive. For more information, see Assembly Versions.
All other elements and attributes seem to be optional.
Additional requirements for the assembly element are:
Its first subelement must be a noInherit or assemblyIdentity element.
The assembly element must be in the namespace
"urn:schemas-microsoft-com:asm.v1". Child elements of the assembly
must also be in this namespace, by inheritance or by tagging.
Finally, there's the longPathAware element which is optional but which should hopefully allow SetCurrentDirectoryW to use long paths:
Enables long paths that exceed MAX_PATH in length. This element is
supported in Windows 10, version 1607, and later. For more
information, see this article.
The section in the docs shows this example xml manifest:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
...
<asmv3:application>
<asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</asmv3:windowsSettings>
</asmv3:application>
...
</assembly>
It doesn't seem to exactly follow the rules from the assembly element:
The assembly element must be in the namespace "urn:schemas-microsoft-com:asm.v1".
Child elements of the assembly must also be in this namespace, by inheritance or by tagging.
Tests
The test environment is:
Windows 10 21H2 x64 19044.1586
VS2022 17.1.1
Windows SDK Version 10.0.20348.0
The test application is a new c++ console application where i made the following change to the Additional Manifest Files:
The source code is very simple; it's also on godbolt but without the manifest:
#include <iostream>
#include <string>
#include <windows.h>
int main() {
std::wstring const path = LR"(H:\test\longPaths\manySmallLongPaths\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\12345678\)";
std::wstring const path2 = LR"(\\?\)" + path;
if (!SetCurrentDirectoryW(path.c_str())) {
printf("Exe SetCurrentDirectory failed 1 - (%d)\n", GetLastError());
if (!SetCurrentDirectoryW(path2.c_str()))
printf("Exe SetCurrentDirectory failed 2 - (%d)\n", GetLastError());
}
}
Trying to put this all together, i think the following file might be a valid Application Manifest:
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns:asmv1='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<asmv1:assemblyIdentity type='win32' name='my.test.app' version='1.0.0.0' />
<asmv1:application>
<asmv1:windowsSettings>
<asmv1:longPathAware>true</asmv1:longPathAware>
</asmv1:windowsSettings>
</asmv1:application>
</assembly>
But compiling and starting the application results in the following error:
The application has failed to start because its side-by-side
configuration is incorrect. Please see the application event log or
use the command-line sxstrace.exe tool for more detail.
Using sxstrace.exe reveals:
INFO: Parsing Manifest File C:\test\longPaths.exe.
INFO: Manifest Definition Identity is my.test.app,type="win32",version="1.0.0.0".
ERROR: Line 2: The element ws1:longPathAware appears as a child of element urn:schemas-microsoft-com:asm.v1^windowsSettings which is not supported by this version of Windows.
ERROR: Activation Context generation failed.
Maybe
Child elements of the assembly must also be in this namespace
is not entirely true (anymore) or i interpreted this wrong. Trying with a completed example from the longPathAware element:
<assembly xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv1:assemblyIdentity type='win32' name='my.test.app' version='1.0.0.0' />
<asmv3:application>
<asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
runs the application successfully, but without long path awareness (windows error code 206 = ERROR_FILENAME_EXCED_RANGE):
Exe SetCurrentDirectory failed 1 - 206
Exe SetCurrentDirectory failed 2 - 206
I checked the final embedded resource but it's definitively there:
To finish
i can only say that i don't know what else to test or if adding longPathAware element to the manifest is even possible with the type of application i'm trying to achieve that.
Maybe there's another api to change the current working folder of my application to a long path, and i would be fine with it, but at least _chdir and std::filesystem::current_path have the same limitations.
Workarounds
Using short names aka. 8.3 aliases might provide a limited work around.
For my cases this is often not feasible because short paths don't need to exists; they can be controlled system wide or per volume:
The general state can be queried with fsutil 8dot3name query
The per volume setting can be queried with fsutil behavior query disable8dot3 c:
Sidenotes
The manifest can be embedded in the executable or a dll.
It will be ignored when the dll containing it is delay loaded.
It will not be ignored by the delay loaded dll when the executable is containing it.
Because the Manifest is "additional" in the project settings, it doesn't need the assemblyIdentity element.
The manifest applies to your application, it allows you to opt in to long path support.
However, long path support must also be enabled system wide. This is the group policy "Computer Configuration > Administrative Templates > System > Filesystem > Enable Win32 long paths".
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001
This design makes no sense but it is what it is. You can't argue that it is in the name of compatibility because one could create long paths with \\?\ since at least Windows 2000.
Native c++ application is using c++/winrt classes to instantiate and use winrt::Windows::Media::Audio::AudioGraph. Inside AudioGraph there is possibility to add effects to graph nodes. There are some already created effects (like echo effect) but there is also possibility to create custom audio effect. Custom audio effect class must be a Windows Runtime Component. There is a way to create custom audio effect in Windows Runtime Component c++/winrt project by creating class with Windows.Media.Effects.IBasicAudioEffect interface in idl file (and providing implementation). This generates winmd, lib and winrt headers files. Until this point everything is fine and working. But to instantiate audio effect it need to be registered and this steep I am missing. Application at runtime throw's an exception with "Class not registered" message when I want to instantiate audio effect class and also throw an exception "Failed to activate audio effect" when I want to instantiate it inside AudioGraph node.
I do not know how to registered Windows Runtime Component from native c++ application.
Steps to create and use custom audio effect are describe here https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/custom-audio-effects. Code is in C# and used in UWP application but it could be converted to c++/winrt almost 1:1.
This article solves this problem:
https://blogs.windows.com/windowsdeveloper/2019/04/30/enhancing-non-packaged-desktop-apps-using-windows-runtime-components/
It is possible to use Registration-free WinRT (starting from Windows 10 1903) by modifying application manifest file (and not Windows Runtime Component Package manifest as suggested in documentation) like this:
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<file name="WinRTComponent.dll">
<activatableClass
name="WinRTComponent.Class1"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="WinRTComponent.Class2"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
</assembly>
Looking for some help from anyone that's worked with SlowCheetah to transform config files under a web project. We're finding that partial config files referenced from the web.config are not being transformed.
For example, we've included references to partial configs AppSettings.config and ConnectionsString.config in the web.config like so:
</system.web>
<connectionStrings configSource ="ConnectionsString.config"></connectionStrings>
<appSettings configSource ="AppSettings.config"></appSettings>
</configuration>
and then in the AppSettings.config we have just the AppSettings section like so:
<appSettings>
<add key="LostPasswordBCC" value="knock#timmons.com" />
</appSettings>
and finally in the transform file AppSettings.Debug.config we have some additions:
<?xml version="1.0" encoding="utf-8" ?>
<!-- For more information on using transformations
see the web.config examples at http://go.microsoft.com/fwlink/?LinkId=214134. -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings >
<add key="Release" value="Something" xdt:Transform="Insert" />
</appSettings>
</configuration>
Obviously the above is just a test to see the transform occur, but what we're finding is that on attempting to preview the transform all we get back is an error "There was an error processing the transformation." The publish attempt also fails.
If we make the config files fully formed xml and not referenced from web.config, the transformation seems to work fine - but were looking to share these files across multiple projects.
Does anyone know if there's a workaround where we can both reference partial configs from the web.config and also have transforms off those partial files? We're dealing with legacy code with a large number of config files across multiple web projects that were attempting to consolidate, thus the need to link from web config to separate shared files.
Problem has been resolved, turns out after help from Sayed, we determined that in our efforts to understand the config transformation process with a web project we had corrupted the transform config file's format. With freshly created config files we were able to get transforms to work using SlowCheetah.
This allowed us to move on the real problem we needed to address which was wanting to transform project configs other than the web.config using Visual Studio 2012's publish profiles. This did not work originally, but again Sayed helped us out and provided a new copy of SlowCheetah that allowed this to work.
Below is a link to the new version of SlowCheetah with the fix: https://github.com/sayedihashimi/slow-cheetah/issues/46
Much thanks for all your time and patience Sayed.
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.