What is a 6210 and 4354 error mean? - visual-studio-2013

http://s4.postimg.org/bkprrelpp/6210.gif
Can someone explain this to me? I set my MCMS.Primary output as instructed by this page.
http://mdc.custhelp.com/app/answers/detail/a_id/19889/~/using-visual-studio-2013-professional-to-build-a-microsoft-visual-basic
I set the registration type to Extract COM information, the Scan At Build to Dependencies and Properties, and checked the COM Interop. But I'm getting an error and a warning after trying to build the project. I tried the help page that pops out after clicking the error message. But I can't find the components view it was referring to. What I want to know is how much important this COM Interop is. And also why sometimes when I build the project the error does not appear. But mostly it does.
One suggestion of that help page told me to register the item mentioned in the error message. An .exe file.

COM extraction is useful for turning self-registration routines into Windows Installer table data. COM Interop is the equivalent for registering managed assemblies for use via COM Interop. In both cases, the resulting registry keys are used to allow other DLLs to instantiate your COM server.
So the fundamental question you have to answer here is whether MCMS.exe is a COM server and registers any such data. If it is and does, then something is wrong with the extraction, and this is a problem. However if MCMS.exe is not a COM server, or does not actually register any relevant COM data, you may need to disable COM extraction.

Related

Limit on number of clrClass'es in manifests for Isolated COM

We have a huge program. Approximately 250 DLLs. Of these, we have approximately 45 COM DLLs and 20+ .NET assemblies that have ComVisible classes in them.
Now we want to work on an XCopy deployable version... WHich means that we need to use Isolated COM. I have been experimenting with smaller projects and have the basic mechanics down of how it works.
Now the problem is that after having built the manifest for one application, it won't load. I used sxsTrace and it gives a useless error message.
Last four lines of sxstrace log:
INFO: Parsing Manifest File c:\src\v13\Debug-Win32\sta_net_DMModel.DLL.
INFO: Manifest Definition Identity is sta_net_DMModel,processorArchitecture="x86",version="1.0.0.0".
ERROR: Activation Context generation failed.
End Activation Context Generation.
The only thing useful is the name of the last DLL manifest it was trying to load. It was a .NET assembly that had a bunch of ComVisible classes in it that are not necessary at startup. I commented it out of the manifest and then the program loaded. But, as I looked at it, I noticed it had nearly 500 clrClass definitions in the manifest for the DLL. I had another DLL that had about a third of that number. I re-included the original DLL in my application manifest but commented out the ~170 clrClass DLL in the application manifest. When I did that, the application loaded to success.
So, it appears to me that there is some kind of limit on the maximum number of clrClass type information that can be loaded from the manifests for Isolated COM. It seems to be a cumulative thing because if I comment out either DLL, then it loads. But if I leave both in, then it won't load.
Is there a documented limit to the amount of type information that the manifest loaders can process?
Is there a registry setting I could change, or some constant I could add to my manifest to bump up the limit? I have no idea what the limit is, but there seems to be one.
Running depends.exe gives this:
Error: The Side-by-Side configuration information for "c:\src\v13\debug-win32\STATIST.EXE" contains errors. 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 (14001).
I eventually found the problem. It was not that there were too many clrClass'es in the manifests. I used ProcMon and PerfView to try and see the problem, but they didn't show much.
Eventually, I just started editing on the manifests and deleting and undeleting clrClass entries from the manifest until I found the problem. I sort of did a binary search...delete half and see if it goes away. If not delete the other half and see if the problem goes away. Then repeat with the problem section and keep halving until the offending clrClass (or clrClasses) is found.
To make a long story short, I found that two different clrClass'es in the two DLLs I was having problems with had the same CLSID. The manifest loader was erroring out because there were COM visible classes in the two DLLs that had duplicate CLSIDs. Somewhere, someone had made a mistake with copy and paste or something. However, the error message from the sxstrace utility did not specify what the error was. It just gave the generic error. To triple check, I wrote a utility to check the CLSID, ProgID, and class names of all the COM visible classes in the two libraries. I eventually found that there were 3 CLSIDs that were duplicates.
So, if anyone ever looks at this in the future, they can see that duplicate CLSIDs (or ProgIDs?) in the clrClass declarations in the .NET assemblies might be their problem.

How to get registration-free COM working in managed/unmanaged interop

I have a unmanaged C++/ATL in-process COM object (in Unmanaged.dll) that I'm trying to use from a managed C# DLL (Managed.dll). However, I want I want to use registration free COM. I have it down to these steps:
Register the COM object on the development machine. The in-process server must have a properly registered type library.
Add a reference to the COM object within the C# project, and then set the Reference Properties to Isolated = True.
This produces Unmanaged.dll, Managed.dll, and Native.Managed.manifest. Opening the manifest, it's pretty clear how the system uses it to load the COM object in a registration-free way.
Here's the rub. I have a managed EXE (Managed.exe) which dynamically loads Managed.dll to access public types. What I mean by "dynamically" is, it uses Assembly.LoadFrom("Managed.dll"). When the code inside Managed.dll tries to create the COM object, it gets a "class not registered" exception. It appears the activation context doesn't get setup correctly when Managed.dll gets loaded.
Is there a way to get registration free COM to work in this scenario?
Two days without an answer, so here's what I've come up with in that time...
It does indeed look like the activation context is setup by the OS at process launch based on the manifest associated with the main EXE. That means all registration-free COM related elements must be in the Main.exe.manifest at the time the process is started. This breaks the isolation between EXE and DLLs. If a DLL is responsible for creating COM objects, you wouldn't expect the EXE manifest to have to contain the reg-free COM information. You might have expected the manifest associated with the DLL to be merged into the process activation context at the time the DLL gets loaded, but it does not.
To work around this, the DLL must configure a new activation context before creating the COM object. To make things worse, there is currently (as of .NET 4.0) no managed way to do this. So, the DLL will have to PInvoke the following Win32 functions:
CreateActCtx
ActivateActCtx
DeactivateActCtx
ReleaseActCtx
I wrapped these calls with a managed class that calls CreateActCtx and ActivationActCtx in the constructor and DeativateActCtx and ReleaseActCtx in IDisposable::Dispose.

Why not embed the typelib into the COM server and only ship it separately?

I'm analyzing a rather old COM server project in order to reuse some stuff from it and noticed a strange thing - in order to expose itself to the registry it implements a separate function different from DllRegisterServer() and that function accepts the path to the typelib and loads the typelib from that path and the typelib is shipped separately and can be located anywhere.
The typical solution is to just use ATL CComModule::RegisterServer() which will happily load the typelib from the same DLL if it is embedded as a resource. The DLL already uses ATL and this should be the most direct way.
I tried to find why the typelib is not embedded as a resource but looks like it was a very old design decision and noone can explain it.
I can see a reason for shipping the typelib separately - this way it's easier for COM server developers to #import it. But why not both ship it as a separate file and embed as a resource into the COM server DLL? I could imagine that the typelib increases the DLL size by several hundred kilobytes but can't find any other serious reason.
What could be the reasons for shipping the typelib as a separate file only?
I finally found a serious reason for shipping a typelib separately only. If two versions - standalone and embedded - are shipped the installer could screw something up and those two typelibs could come out of sync and this would cause all kinds of weird problems for customers. Shipping exactly one version of typelib is safer in this aspect.

Getting CLSID for a DLL file?

I want to create a small app to add and remove user defined context menu entries from the registry. To make this, somehow I need to get the CLSID of an arbitrary DLL so I can back up previous entries if they exist before writing new ones.
Although regsrv32 somehow manages to create this magical number, I didn't find any way to get that number myself.
I hope there is something better than this:
scanning registry for the DLL name
if not found, register it, scan again, and then unregister it again
If the DLL has been renamed, I can see a possibility for problems.
You could consider calling LoadTypeLibEx on the DLL specifying REGKIND_NONE and then examine get the TypeLibInfo information available via the ITypeLib interface passed back to you.
There's some information about this sort of thing on MSDN. It's an old VB6-focused link but has useful information about inspecting COM components in this way.
You could try to use RegOverridePredefKey() to intercept what regsvr32 does to the registry - call RegOverridePredefKey(), then reproduce what regsvr32 does - LoadLibrary() the COM server, call DllRegisterServer() - then inspect the changes done. With RegOverridePredefKey() you will isolate the changes and not let them become persistent.

CComPtr CoCreateInstance() fails

I have a COM .dll registered successfully with regsvr32 but somehow CoCreateInstance() fails to create one of its interfaces. Is there a freeware tool which can determine the reason for the failure?
First of all, check the return value of the CoCreateInstance() call. Second, you can use a tool like Regmon or Process Monitor to see what registry lookup fails. This way, you can quickly determine what exactly wasn't registered the way you'd expect it to be.
If your com dll is implemented in C++ & has debug info, you could also try debugging with MSVC to step into CoCreateInstance.
My guess is that you missed associating your class with one of the interfaces properly. I've done that a number of times by mistake. If you're using ATL you need to make sure your implementing class derives from the interface & also you have added COM_INTERFACE_ENTRY(I____) for your interface in the COM_MAP:
BEGIN_COM_MAP(CFileHelper)
COM_INTERFACE_ENTRY(IFileHelper)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IStream)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
END_COM_MAP()
Or maybe the GUID differs between the IDL file and what's in the implementing C++ file. MSVC6 has an annoying bug where if the wizard fails to create a new class because of file permissions (e.g. some of the files it wants to change are read-only) but it has already added a GUID to the IDL file, and you fix the file permissions and go to do it again, there will be an inconsistency in the GUIDs and it's a pain to catch this. In an ideal world, the GUID definitions would reside ONLY in one file and then you wouldn't have to worry about this.
If not that, sometimes there are weird errors regarding marshaling & apartments but that only pops up if you've got multiple threads and are sending interface pointers across thread or interface boundaries.

Resources