After many tests that go through various samples with Microsoft support, I found many errors that occur when trying to implement a managed COM server with an unmanaged C ++ COM client. Here are the key pieces of information that I remember that can be applied to the sample code in the question to make sure it works.
- The client should not use isolated COM parameters in a C ++ project. My memory fades, but Microsoft support tells me that this is for something else - I think, to develop an isolated COM interface for an unmanaged COM server instead of a managed COM server. Although this is not entirely clear from his description at https://msdn.microsoft.com/en-us/library/zzbcs3x5(v=vs.120).aspx .
- The client can select "Yes" or "No" for the "Insert manifest" option, but if "Yes" is selected, then the manifest, which includes the dependent assembly, must be provided as an input manifest file. If the embedded manifest does not contain dependent assembly information, then any external manifest file will be ignored. Also, make sure that the configuration (e.g. Debug) that is being edited matches the configuration you are testing!

- If the COM server is signed with the key (strongly named), then the assemblyIdentity element in both the client manifest and the server manifest must contain publicKeyToken, otherwise HRESULT error 0x80131040 will occur during CoCreateInstance.
- Embedding the RT_MANIFEST resource as a Win32 resource in managed code is not easy with Visual Studio 2013, because C # and VB.NET projects usually want to inject resources as managed .NET resources, not Win32 resources (you can check this by opening the output DLL file using the resource viewer and note that .NET executables usually get a version resource and not much more, even if a manifest file is included in the project). One way around this is to create an RC file as follows:
-
#define RT_MANIFEST 24 #define MANIFEST_RESOURCE_ID 1 MANIFEST_RESOURCE_ID RT_MANIFEST ClassLibrary1.manifest
Then add the pre-build step as follows:
"C:\Program Files (x86)\Windows Kits\8.1\bin\x86\rc.exe" "$(ProjectDir)ClassLibrary1.rc"
Then, on the Application Settings tab of the Project tab, change the Resources to use ClassLibrary1.res instead of Icon and Manifest. But this is due to problems: firstly, the path to RC.EXE is not easy to determine without hard coding; secondly, version information from AssemblyInfoCommon will be ignored, since the resources in the RC file completely replace all Win32 resources that will be generated by the .NET compiler.
Another possibility is to simply save the manifest file of the server’s COM server separately and do not embed it as a resource. I read that this may be unreliable, but it works on the 64-bit version of Windows 7 Enterprise.
- To ensure that the unmanaged client loads the correct .NET runtime, it needs a configuration file (
ConsoleApplication1.exe.config ) that determines how to load .NET. For .NET 4.5, I saw this work:
-
<configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/> </startup> </configuration>
Whereas for .NET 3.5 it seems like you need to switch LegacyV2RuntimeActivationPolicy:
<configuration> <startup useLegacyV2RuntimeActivationPolicy="false"> <supportedRuntime version="v3.5"/> </startup> </configuration>
It is important to check the synchronization of all frameworks and CLR versions. And it’s important to understand that the CLR versions do not match the framework versions. For example, if you want to create a managed COM server on .NET 3.5, the CLR version (runtimeVersion) should be "2.0.50727", but the .NET version (supported by Runtime) should be "v3.5".
Verify that the target version of the COM server COM server matches the client supported by Runtime. If it is created from the command line, it may not select the version of the frame from the Visual Studio project file (for example, if you use the C # VB.NET compiler directly, and do not call MSBuild), make sure that the assembly is aimed at the correct version of the framework.
I have not yet confirmed all of the above, but I intend to go through the whole process in the near future to verify that I caught everything. Here's what I ended up with not mentioning yet:
ConsoleApplication1.exe.manifest (in the source directory, copied or pasted into the output directory during build)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity type = "win32" name = "ConsoleApplication1" version = "1.0.0.0" /> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="ClassLibrary1" version="1.0.0.0" publicKeyToken="541b4aff0f04b60a"/> </dependentAssembly> </dependency> </assembly>
ClassLibrary1.manifest
<?xml version="1.0" encoding="utf-8"?> <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> <assemblyIdentity type="win32" name="ClassLibrary1" version="1.0.0.0" publicKeyToken="541b4aff0f04b60a" /> <clrClass clsid="{81723475-B5E3-4FA0-A3FE-6DE66CEE211C}" progid="ClassLibrary1.Class1" threadingModel="both" name="ClassLibrary1.Class1" runtimeVersion="v2.0.50727"></clrClass> </assembly>
EDIT:
Now go through and check every detail with full error information, etc.
I will start by creating a single solution containing two projects with all the default values ​​and the code indicated in the question. I start without the manifest files or any of the project parameters mentioned in the question, and explicitly invoke when I make these changes to the process below. These are the steps and errors that are on the way to making this project work.
- Error: "Class1: Undeclared identifier". You must run the Developer Command Prompt command prompt and run the following command line to get a TLB file that can import C ++ code:
tlbexp ClassLibrary1.dll - Move the TLB file to the ConsoleApplication1 project directory and reassemble. The same mistake.
- Replace the angle brackets with
#import <ClassLibrary1.tlb> raw_interfaces_only quotation marks so that it #import "ClassLibrary1.tlb" raw_interfaces_only . Rebuild: Success. - At this point, if we run, we get
Error 80040154 (the class is not registered), because we did not register the component and did not install COM without registering. - Knowing that an attempt to create an isolated COM in the client will present
Error 800401f9 , we will skip this and just try to create a client manifest. Create a new text file with the following contents and save it as ConsoleApplication1.exe.manifest in the project directory of ConsoleApplication1:
-
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity type="win32" name="ConsoleApplication1" version="1.0.0.0" /> <dependency> <dependentAssembly> <assemblyIdentity name="ClassLibrary1" version="1.0.0.0" /> </dependentAssembly> </dependency> </assembly>
- At this point, it seems the steps mentioned earlier in this solution are a bit more complicated. You can simply include the manifest file in the project by showing hidden files and using the "Include in project" command in the manifest file.
- At this point, the error message "Application failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the sxstrace.exe command line for more details." This is partly due to the fact that we do not put ClassLibrary1.dll somewhere where ConsoleApplication1.exe can find it. The output from sxstrace parsing at this point is as follows:
-
INFO: Parsing Manifest File C:\Users\bmarty\Documents\Visual Studio 2013\Projects\RegFreeCOM\Debug\ConsoleApplication1.exe. INFO: Manifest Definition Identity is ConsoleApplication1,type="win32",version="1.0.0.0". INFO: Reference: ClassLibrary1,version="1.0.0.0" INFO: Resolving reference ClassLibrary1,version="1.0.0.0". INFO: Resolving reference for ProcessorArchitecture ClassLibrary1,version="1.0.0.0". INFO: Resolving reference for culture Neutral. INFO: Applying Binding Policy. INFO: No binding policy redirect found. INFO: Begin assembly probing. INFO: Did not find the assembly in WinSxS. INFO: Attempt to probe manifest at C:\Users\bmarty\Documents\Visual Studio 2013\Projects\RegFreeCOM\Debug\ClassLibrary1.DLL. INFO: Attempt to probe manifest at C:\Users\bmarty\Documents\Visual Studio 2013\Projects\RegFreeCOM\Debug\ClassLibrary1.MANIFEST. INFO: Attempt to probe manifest at C:\Users\bmarty\Documents\Visual Studio 2013\Projects\RegFreeCOM\Debug\ClassLibrary1\ClassLibrary1.DLL. INFO: Attempt to probe manifest at C:\Users\bmarty\Documents\Visual Studio 2013\Projects\RegFreeCOM\Debug\ClassLibrary1\ClassLibrary1.MANIFEST. INFO: Did not find manifest for culture Neutral. INFO: End assembly probing. ERROR: Cannot resolve reference ClassLibrary1,version="1.0.0.0". ERROR: Activation Context generation failed. End Activation Context Generation.
- Copying ClassLibrary1.dll to the same directory as ConsoleApplication1.exe does not change anything, because we did not provide a manifest for the file with which the COM dependency can be identified. So the next step is to create a manifest for ClassLibrary1. One version of ClassLibrary1.manifest is already present in this question. Try this by creating a text file with this content and save it in the project directory of ClassLibrary1 as ClassLibrary1.manifest. To include it in a project, try the simple “Include in Project” command (again, by turning on the visibility of hidden files to make this possible). Now, what happens when you copy the new ClassLibrary1.dll to a directory with ConsoleApplication1.exe and start up?
- The same sxstrace errors and results occur because the manifest file in the managed DLL is not embedded as a Win32 resource, as you can verify by opening the DLL file with Visual Studio, which displays Win32 files. It shows the resource version and nothing more. Therefore, let it exclude the manifest from ClassLibrary1 and simply copy the manifest file to the ConsoleApplication1.exe folder instead.
- Success! The program starts and ends normally. But what if we want to use a component built with a different version of the .NET framework. Or maybe your test does not work at this moment, because your Visual Studio was by default a different version? Now I see that my ClassLibrary1 project was .NET 3.5 by default. What happens if I change it to 4.0, rebuild, copy and run again?
- Error 8013101b is running. This matches (according to google search) with COR_E_NEWER_RUNTIME, which also means that "The module specified in the manifest was not found." This happens when, for example, an EXE that loads .NET 2.0 tries to reference a DLL built with .NET 4.0. So now we have to tell the uncontrolled EXE client which version of the .NET platform to download, since it solves its link to COM. This is done using the ConsoleApplication1.exe.config configuration file. Just create a new text file and save it with this name in the ConsoleApplication1.exe directory. It has the following contents:
-
<configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/> </startup> </configuration>
The same error will occur if the use of LegacyV2RuntimeActivationPolicy is excluded in this case. Unfortunately, I do not quite understand why, but I suspect that this is due to the new v4.0 runtime activation policy, by default for downloading CLR v2.0, if the downloaded executable file does not explicitly reference .NET 4.0 (managed code not because it doesn’t explicitly refer to the .NET period).
- Success again! But wait, there still. What if your COM library is signed with a key (has a strong name)? Add the key to ClassLibrary1, configure it to sign the DLL on the Signing tab, and see what happens when we copy the updated DLL to the ConsoleApplication1.exe directory.
- Now we get Error 80131040 ("The specific definition of the assembly manifest does not match the assembly reference"). Both sxstrace and fuslogvw are useless useless here, giving any information about what is going on. Fortunately, I now know that in this particular reg-free-com script, this is caused by the absence of the publicKeyToken attribute for assemblyIdentity elements that describe ClassLibrary1 (in both manifest files). But how do you get the publicKeyToken value? Run
sn -T ClassLibrary1.dll from the developer's command line. After updating ClassLibrary1.manifest and ConsoleApplication1.exe.manifest, remember to rebuild ConsoleApplication1.exe if the manifest is built-in, and copy ClassLibrary1.manifest to the ConsoleApplication1.exe directory. Run again and? - I went through a few more error resolution cycles with sxstrace, but that was due to stupid errors. In the interest of others who make stupid mistakes, here are a few more things to know if you get sxstrace errors: a) make sure you use the
publicKeyToken attribute and not some other funny name like privateKeyToken ; b) Ensure that all attributes specified in the assemblyIdentity server-side manifest match the attributes on the client-side manifest and that you do not have type="win32" specified on one and not the other. - Success! Output signal
B Inserted obby
It should also be noted that the VB6 client also works using the following files with the VB6 client:
Project1.exe.config:
<configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/> </startup> </configuration>
Project1.exe.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="Project1" version="1.0.0.0" /> <dependency> <dependentAssembly> <assemblyIdentity name="ClassLibrary1" version="1.0.0.0" publicKeyToken="541b4aff0f04b60a" /> </dependentAssembly> </dependency> </assembly>
However, there seems to be a tendency to report “ActiveX component cannot create the object” (runtime error 429) in rare cases when an executable file is created and launched before the creation of the configuration and manifest files. Restoring an EXE file seems to fix it, but I cannot get the problem back, so it’s hard to determine the exact cause.
I thought that I was a good enough solution to the problems, but something about the numerous moving parts and the many useless error codes and error messages reported in reg-free com configuration problems makes it almost impossible to determine without any solid experience , or Microsoft source code. Hope this answer helps others gain similar experiences. Please circulate this answer if you find out more!
Appendix 1
A managed COM server manifest can be correctly and easily implemented if you use the Add → New Item ... command in a project to add an Application Manifest File. This adds a file called app.manifest to the project. But the real tricky part is that it does it in a way that cannot be replicated in any other way using the Visual Studio interface, with the exception of one virtuoso workflow. Since the Manifest field on the Application tab of the project settings window is disabled for projects of the Class Library type, the manifest, which is usually installed here, cannot be set for the class library. But you can temporarily change the project to a Windows application, change it here, and then return it to the class library. The parameter will be set so that the selected manifest is inserted correctly. You can check the settings in a text editor by viewing the project file. Search for:
<PropertyGroup> <ApplicationManifest>app.manifest</ApplicationManifest> </PropertyGroup>
Appendix 2
Error 0x80131040 can still occur with all the above precautions. To narrow down the reason for this, it helps to use the merge log viewer to see more information about what happens when assemblies are loaded and resolved. Google "Fuslogvw" for more information on how to view this log (fuslogvw.exe is a utility provided during the installation of Visual Studio). It is also important to understand that this default application does not seem to display any information until you configure it to write information to files, reproduce the problem, and then restart the application to read the log files after they are created. And, according to the MSDN documentation, it is also important to remember this utility as an administrator.
Once you have overcome all the obstacles to running fuslogvw.exe, you can see something like this in the log:
WRN: Comparing the assembly name resulted in the mismatch: Major Version ERR: The assembly reference did not match the assembly definition found. ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.
Although the COM server manifest file is specified in version 1.0.0.0, it is not the (only) version used when linking from the COM client link to the server. My client EXE file tried to reference 1.0.0.0, which exactly matched the version in the COM server manifest file, but didn’t match the .NET version of the DLL. After fixing the client and server manifest files to reflect the actual version in the .NET DLL, error 0x80131040 disappeared and fuslogvw.exe became the key to identifying this source of the problem.
If the client manifest is synchronized with the real version of the .NET DLL, but the manifest file of the DLL server does not reflect this version, another error will occur:
The application did not start because its side-by-side configuration is incorrect. See the application event log or use the sxstrace.exe command-line tool for more details.
Appendix 3
Error 0xc0150002 or the following message may appear:
The application failed to start correctly (0xc0150002), click "OK" to close the application.
I saw this when the client manifest was embedded in an unmanaged DLL, and not in an unmanaged EXE, and the manifest assemblyIdentity element did not exactly match the assemblyIdentity server. The client had an additional processorArchitecture="x86" in which the server did not indicate, causing a mismatch. Unfortunately, I don't know how to find out without daring to check the manifest files to make sure they match (or read this article). This error does not explicitly indicate that the manifest file is the source of the problem, so you just need to know that there is a possible correlation between this error message and this reason.
Appendix 4
I saw that external manifest files are completely ignored, giving a completely empty sxstrace log, even if there are no built-in manifests in the executable files. , - ( http://csi-windows.com/blog/all/27-csi-news-general/245-find-out-why-your-external-manifest-is-being-ignored ). , , :
copy /b myfile.exe+,,
5
Not Registered ( 0x80040154 - REGDB_E_CLASSNOTREG ), CoCreateInstance :
- CPP , ,
DllMain , CPP . .cctor , /clr . - DLL , COM, Reg-Free COM.
- COM-DLL ( COM-Callable Wrapper aka CCW) .NET 2.0.
- EXE, DLL, , Reg-Free, COM.
- COM- DLL
regasm . - CPP ,
CoCreateInstance , /clr , ++.
- 3 , . ( , , - # 1 - CLR ). , Class Not Registered , , 3 . Note. # 6. , # 1. , ( CoCreateInstance ) DLL - Not Registered, DLL , /clr . CPP ++, COM- . , COM, .NET-.