debugging COM free registration (c++)
Asked Answered
Q

2

7

I've built a COM client application that uses two COM server dlls; I want this application to run without COM registration - ie: winsxs / .manifests

I get a (...almost expected...) "Class not registered" message when I try to create an instance of my COM object from my client application.

I've already succeeded that kind of configuration before but I cannot figure out why this one fail.


here are a few more details:

  • the modules I have:
    • a MFC client that depends on 2 COM servers (dll1.dll and dll2.dll)
    • dll1.dll COM server depends on dll2.dll
    • dll2.dll has no COM dependency

the COM objects I have:

  • in dll1.dll (.idl language)

-

[
    object,
    uuid(262D00FB-3B9F-4A76-98FC-3051FDCAF0A6),
    dual,
    nonextensible,
    helpstring("IDialogManager Interface"),
    pointer_default(unique)
]
interface IDialogManager : IDispatch{
};
[
        uuid(58562535-BCA5-4D04-BB92-78F90EDA201E),
        //...
]
dispinterface _IDialogManagerEvents
{
};
[
        uuid(D599D3F0-A4D1-44A7-87A9-16032CC613CA),
        //...
]
coclass DialogManager
{
        [default] interface IDialogManager;
        [default, source] dispinterface _IDialogManagerEvents;
};

-

  • in dll2.dll

-

[
    object,
    uuid(2A183A2E-A620-4E00-B657-C9D2E59201D4),
    nonextensible,
    helpstring("ICadWizardsManager Interface"),
    pointer_default(unique)
]
interface ICadWizardsManager : IDispatch{
};
[
    object,
    uuid(FE97F3FB-8930-43BC-947D-64C90F45A071),
    nonextensible,
    helpstring("ICadWizard Interface"),
    pointer_default(unique)
]
interface ICadWizard : IDispatch{
};
[
    uuid(5365D4E6-ADFB-4429-9DEA-C44CC94AA3EF),
]
dispinterface _ICadWizardEvents
{
};
[
    uuid(CAC2D0BF-AD5B-4CC8-A04D-53AB23A0CDF4),
]
coclass CadWizard
{
    [default] interface ICadWizard;
    [default, source] dispinterface _ICadWizardEvents;
};
[
    uuid(3164FAC4-6F5F-4E4D-9B09-DC4115850D78),
]
dispinterface _ICadWizardsManagerEvents
{
};
[
    uuid(707CB6C8-311E-45EC-9DCB-50477F588BAF),
]
coclass CadWizardsManager
{
    [default] interface ICadWizardsManager;
    [default, source] dispinterface _ICadWizardsManagerEvents;
};

-

  • the client call

-

IDialogManagerPtr dialogManager;
dialogManager.CreateInstance(CLSID_DialogManager); // <<< returns "Class not registered"

-

  • the client.exe.2.manifest

-

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

<assemblyIdentity name="client" version="1.0.0.0" type="win32" processorArchitecture="x86"/>
<file name="dll2.dll">
 <comClass
     clsid="{707CB6C8-311E-45EC-9DCB-50477F588BAF}"
     threadingModel="apartment">
 </comClass>
 <comClass
     clsid="{CAC2D0BF-AD5B-4CC8-A04D-53AB23A0CDF4}"
     threadingModel="apartment">
 </comClass>
</file>

<file name="dll1.dll">
 <comClass
     clsid="{D599D3F0-A4D1-44A7-87A9-16032CC613CA}"
     threadingModel="apartment">
 </comClass>
</file>

</assembly>

-


I have no error during sxs activation context generation: - no error in windows log (should means that my manifest syntax is correct) - no error detected by sxstrace (the log ends with "INFO: Activation Context generation succeeded." message and contains no error or sucpicious message; moreover, I see that my manifest is loaded correctly)

Any idea?

is there a way to debug sxs deeper that with sxstrace? getting the list of actually registered com or clr classes for instance???

Thank you by advance

Quart answered 16/2, 2011 at 16:17 Comment(2)
Are you implementing dual interfaces?Toreutic
I've edited my post to add the full idl definition of IDialogManager, ICadWizardsManager and ICadWizard; which are the interfaces I implementQuart
D
2

There are usually - at least - two manifests involved when building the activation context for registration free COM.

There is the EXE manifest, that specifies its dependent assemblies, including the assembly containing the COM components, and there is the assembly manifest, describing the dll's, window classes, and COM objects in the assembly.

This Blog contains information about what the .2 means. Basically, when the system looks for a manifest, it looks for modulename.exe[.resid].manifest - In the case that resid is 1, it is omitted.

So, you are using MFC, which means DevStudio, which means that your project should already be configured to produce a RT_MANIFEST resource automatically with the c-runtime and common control 6 settings in it.

Visual Studio 2005 supports this syntax to merge dependentAssembly elements with your applications manifest without having to try and merge XML directly:

#pragma comment(linker, \
    "\"/manifestdependency:type='Win32' "\
    "name='client' "\
    "version='1.0.0.0' "\
    "processorArchitecture='*' "\
    "language='*'\"")

So, if you add that to a cpp or header in your .exe, and then save your client.exe.2.manifest as "client.manifest", you should be all systems go.

Danais answered 17/2, 2011 at 20:11 Comment(0)
D
7

The simple explanation is that the .manifest file isn't being used. Which is highly likely in this scenario, your .exe almost certainly already contains a manifest, embedded as a resource. Very common for a MFC app to enable visual styles. And for code compiled by the VS2005 or 2008 compilers which embeds a manifest to find the runtime DLLs.

To verify this, use File + Open + File and select the compiled .exe file. Look for the RT_MANIFEST node. If Windows finds such an embedded manifest it isn't going to continue looking for a file-based one. You need to merge your regfree COM entries into the embedded one. I wish I could give you a good MSDN Library link but the docs about manifests suck serious rock.

Dogmatist answered 16/2, 2011 at 18:44 Comment(10)
+1 for a useful answer; and I would give +10 for "the docs about manifests suck serious rock" :-)Concession
Is this valid even if sxstrace logged that my manifest has been parsed correctly?Quart
In my mind, sxstrace clearly indicates that the manifest is actually used. As far as I understand when I monitor the application load (procmon) It seems that windows looks for client.exe.manifest if there's no RT_MANIFEST res; otherwise, it looks for client.exe.2.manifest. So in my mind, "external" manifest are used even if embeded manifests existsQuart
I've double checked the other mfc .exe that works the same way; it contains a RT_MANIFEST as well.Quart
I'm 95% sure, can never be 100%. Using ".2.manifest" is also extraordinarily strange. No clue why Windows would like ".2" This kind of stuff tends to work by accident if the registry isn't thoroughly cleaned. Use SysInternals' ProcMon utility to see where the path is coming from. That should never be from a key named InprocServer32.Dogmatist
this is documented somewhere in the jungle, windows assigns an index for each embedded manifest it found (an app can contain more tha one) and then looks for .X.manifest files where X is the next free manifest index; moreover, it tries to load next X+1.manifest as far as it finds X.manifest! and it stops at 15??- more than you said: reg free suck serious rock! They announced the end of dll hell!! a joke probably! It looks cheaper and simpler to put 2 computer side by side tan two COM dlls... I'll try to browse my history to find the doc...Quart
I dunno, sounds crazy, not sure I want to know about it :/ It still isn't clear to me how you proved that the .manifest actually gets loaded. sxstrace only logs failures. Why don't you make an intentional mistake, screw up an element name.Dogmatist
Hi, here is the link where I red the explaination of the ".2." : #2101473 obviously; I thought it was in msdn - how naive I was. Unfortunately there are no doc references in this post. Anyway, first I forgot to thank you Hans for your answers, so - THANK YOU!! :), then, both sxstrace and procmon indicate that my manifest is actually used: procmon shows me my app opens the file, sxstrace logs me syntax errors (tested as you suggested) or logs success otherwise.Quart
I'd just stop trying to make this work the Hard Way. Use one manifest and embed it. Known to work well. Good luck.Dogmatist
I give up (I've no more prozac) - My conclusion is you were right even if my manifest is loaded and parsed; it is not actually used. Thank you againQuart
D
2

There are usually - at least - two manifests involved when building the activation context for registration free COM.

There is the EXE manifest, that specifies its dependent assemblies, including the assembly containing the COM components, and there is the assembly manifest, describing the dll's, window classes, and COM objects in the assembly.

This Blog contains information about what the .2 means. Basically, when the system looks for a manifest, it looks for modulename.exe[.resid].manifest - In the case that resid is 1, it is omitted.

So, you are using MFC, which means DevStudio, which means that your project should already be configured to produce a RT_MANIFEST resource automatically with the c-runtime and common control 6 settings in it.

Visual Studio 2005 supports this syntax to merge dependentAssembly elements with your applications manifest without having to try and merge XML directly:

#pragma comment(linker, \
    "\"/manifestdependency:type='Win32' "\
    "name='client' "\
    "version='1.0.0.0' "\
    "processorArchitecture='*' "\
    "language='*'\"")

So, if you add that to a cpp or header in your .exe, and then save your client.exe.2.manifest as "client.manifest", you should be all systems go.

Danais answered 17/2, 2011 at 20:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.