1
votes

I have an ATL COM library that defines an enum and an interface in MIDL like:

[uuid(65785D49-574A-4B1B-95F1-B9C7F283364A)]
typedef enum Options
{
    Option1,
    Option2
} Options;

[
    object,
    uuid(2E3D1B1A-DF95-434F-836B-73FF1245B608),
    oleautomation,
    nonextensible,
    pointer_default(unique)
]
interface IExample : IUnknown
{
    HRESULT Test([in] Options option, [out, retval] BSTR* str);
};

I then create a managed assembly and reference the TLB, which creates a PIA and embeds the types (Embed Interop Types = true) into the managed assembly.

In the managed assembly, I now create a class that implements the interface:

public class Example : IExample
{
    public string Test(Options option)
    {
        return option.ToString();
    }
}

Now I would like to create a third assembly that references the managed assembly and creates the object and call into it, but it doesn't let me since Options is an unreferenced type (requires me to include the PIA generated from the typelib):

public class Equivalence
{
    public void UseTest()
    {
        Example e = new Example();
        e.Test(Options.Option1);    // recognizes that it requires an ExampleLib.Options parameter, but that type isn't available
    }
}

Using reflector, I can see it inside the managed assembly, but it isn't viewable by object browser:

namespace ExampleLib
{
    [ComImport, CompilerGenerated, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("2E3D1B1A-DF95-434F-836B-73FF1245B608"), TypeIdentifier]
    public interface IExample

    [Guid("65785D49-574A-4B1B-95F1-B9C7F283364A"), CompilerGenerated, TypeIdentifier("15a6cf97-c415-4866-bdfb-7da65edb1faa", "ExampleLib.Options")]
    public enum Options
}

My managed assembly is itself a library intended to be distributed as an API, and I would like to expose this enumeration and interface so that it can be used by outside parties without having to deliver the PIA generated from the typelib of the ATL COM library. Is it possible?

1
Do not embed the types! Because you want to distribute the ATL library together with your API, it is not what you want anyway. Only the types used in the assembly referencing your TLB are embedded and therefor clients would possibly miss certain objects. Instead you should create a PIA from your TLB, deploy it to the GAC and reference it in each assembly you want to consume it's types.Carsten
We don't need (or want) external customers to use the ATL library at all, their only access should be through our managed API. Therefore, the only types we need to expose through this API are the ones being embedded. I'm slowly coming to the conclusion that I'd need to distribute the PIA for this to work but I was hoping that it could be embedded in the assembly to reduce the dependencies.mford
The only thing you can embed into your assembly are Interop-types, which are different from the underlying COM types! The ATL library must be deployed and registered to the client anyway, even if you are embedding the interop types (which are just wrappers around the COM library). Because of this clients are able to directly access your unmanaged type library. The only way to control this is by generating and distributing a PIA. Dependencies are no argument here - they are a result of the nature of your solution. You cannot reduce them by leaving out certain components.Carsten

1 Answers

1
votes

Apparently this cannot be done. One of the errors (CS1748) pointed me to this post which says the PIA must be linked in by both assemblies.