c++winapicmakedllmt

How do I correctly reference a private Windows assembly in the Application Manifest?


My setup and what I try to achieve

My project is set up to use CMake, Ninja as my generator and MSVC as my compiler. I have an executable target A.exe and 2 shared library targets (B.dll and C.dll). I'm on Windows and use load-time linking by linking to their static counterparts B.lib and C.lib. The dependency of this targets goes as follows: A.exe -> B.dll -> C.dll (read "->" as "depends on").

Everything compiles and builds successfully, but when I try run the program I get this error:

The Application has failed to start because its side to side configuration is incorrect

The basic folder structure of my project:

\
 | - A.cpp
 | - B.cpp
 | - C.cpp
 | - A.manifest
 | - B.manifest
 | - C.manifest
 | - CMakeListst.txt

Code

CMakeLists.txt:

cmake_minimum_required(VERSION 3.22.0)
project(test VERSION 0.1.0)

add_executable(
    A
    "A.cpp"
    "A.manifest"
)


add_library(
    B
    SHARED
    "B.cpp"
    "B.manifest"
)

add_library(
    C
    SHARED
    "C.cpp"
    "C.manifest"
)

target_link_libraries(B C) # B -> C
target_link_libraries(A B) # A -> B

CPP files

A.cpp:

__declspec(dllimport) void B_test();

int main()
{
    B_test();
    return 0;
}

B.cpp:

__declspec(dllimport) void C_test();

__declspec(dllexport) void B_test()
{
    C_test();
}

C.cpp:

#include <iostream>

__declspec(dllexport) void C_test()
{
    std::cout << "Success" << std::endl;
}

Manifests

A.manifest:

<?xml version="1.0" encoding="UTF-8"?>
<assembly
        xmlns="urn:schemas-microsoft-com:asm.v1"
        manifestVersion="1.0"
        >

    <assemblyIdentity
            type="win32"
            name="A"
            language="*"
            processorArchitecture="amd64"
            version="1.0.0.0"
            />
            
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                    type="win32"
                    name="B"
                    language="*"
                    processorArchitecture="amd64"
                    version="1.0.0.0"
                    />
        </dependentAssembly>
    </dependency>

</assembly>

B.manifest:

<?xml version="1.0" encoding="UTF-8"?>
<assembly
        xmlns="urn:schemas-microsoft-com:asm.v1"
        manifestVersion="1.0"
        >

    <assemblyIdentity
            type="win32"
            name="B"
            language="*"
            processorArchitecture="amd64"
            version="1.0.0.0"
            />

    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                    type="win32"
                    name="C"
                    language="*"
                    processorArchitecture="amd64"
                    version="1.0.0.0"
                    />
        </dependentAssembly>
    </dependency>

    <file name="B.dll" />

</assembly>

C.manifest:

<?xml version="1.0" encoding="UTF-8"?>
<assembly
        xmlns="urn:schemas-microsoft-com:asm.v1"
        manifestVersion="1.0"
        >
    <!-- details about our side-by-side assembly-->
    <assemblyIdentity
            type="win32"
            name="C"
            language="*"
            processorArchitecture="amd64"
            version="1.0.0.0"
            />

    <file name="C.dll" />
</assembly>

What I tried

What I wanted is to make my A.exe depend on B.dll which also depends on C.dll. I would like to know where I'm wrong and what can I do to achieve my goal.


Solution

  • With the help of fellow programmers in the comments and a bit of adding and removing lines from .manifest files I finally made it work. Thanks to Simon Mourier

    A should declare B and C dlls – Simon Mourier

    What I was wrong about is declaring my B.dll and C.dll as separate private assemblies. What I had to do, in fact, is add the <file> tags to A.manifest as follows:

    <?xml version="1.0" encoding="UTF-8"?>
    <assembly
            xmlns="urn:schemas-microsoft-com:asm.v1"
            manifestVersion="1.0"
            >
    
        <assemblyIdentity
                type="win32"
                name="A"
                language="cpp"
                processorArchitecture="amd64"
                version="1.0.0.0"
                />
        <!-- Added the .dll's to application manifest -->
        <file name="B.dll" />
        <file name="C.dll" />
    
    </assembly>
    

    Also, the B.manifest and C.manifest were no longer needed, and I excluded them from the build:

    cmake_minimum_required(VERSION 3.22.0)
    project(test VERSION 0.1.0)
    
    add_executable(
        A
        "A.cpp"
        "A.manifest"
    )
    
    # removed "B.manifest"
    add_library(
        B
        SHARED
        "B.cpp"
    )
    
    # removed "C.manifest"
    add_library(
        C
        SHARED
        "C.cpp"
    )
    
    target_link_libraries(B C) # B -> C
    target_link_libraries(A B) # A -> B
    

    With that, everything works just fine and outputs correct