How to access a CoClass that exposes multiple interfaces through COM InterOp? - com

I've got a CoClass that is describes as below:
[
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
version(1.0),
helpstring("FooBar")
]
coclass FooBar
{
[default] interface IFoo;
interface IBar;
}
So my questions are:
Why does tlbimp only expose the IFoo interface, while oleview.exe shows both interfaces?
Does tlbimp only expose [default] interfaces and why? (According to the MSDN [default] "is intended for use by macro languages.")
How can I model this case in MIDL/COM? Should I use association instead of inheritance?

Related

Inheritance and visibility of interfaces

The task is to hide Library1 interface1 behind the facade of Library2.
Full source here https://bitbucket.org/tim4dev/inheritance-interfaces/src/master/
(Library1) interface1
(Library2) interface2 : interface1
(Library2) Klass2: Interface2
(application)
implementation project(":library2")
class KlassApp constructor(
private val klass: Interface2
) {
fun klassAppFun() {
klass.interface1fun1()
}
}
We get an error
KlassApp.kt: Unresolved reference: interface1fun1
Question: what are the standard patterns to hide Library1 behind the facade of Library2 ?
You need to choose:
make Library1 an api dependency of Library2, not implementation as you currently have it (so not hide it fully);
if you want to hide it, you can't expose any types of Library1 in public parts of Library2, which includes extending its interfaces.
See the documentation for the difference of api and implementation:
So when should you use the api configuration? An API dependency is one that contains at least one type that is exposed in the library binary interface, often referred to as its ABI (Application Binary Interface). This includes, but is not limited to:
types used in super classes or interfaces
types used in public method parameters, including generic parameter types (where public is something that is visible to compilers. I.e. , public, protected and package private members in the Java world)
types used in public fields
public annotation types

COM coclass implementing interface from another type library

I'm relatively new in COM, so appologies if this is a stupid question. I'm having a bunch of COM interfaces compiled into a type library A. This type library is a resource in one of the DLLs (a.dll) in my solution. In a separate type library (B) that goes into a separate DLL (b.dll) I would like to define a coclass that implements an interface from type library A. See the IDL code below as a simplified example of what I have in mind:
import "oaidl.idl";
import "ocidl.idl";
// Import IMyInterface, which is part of MyLibA.tlb
import "MyInterface.idl";
[
uuid(E80492A8-1E8C-4ABF-B4DE-9C252C445AFE),
version(1.0),
helpstring("MyLibB Type Library")
]
library MyLibB
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
importlib("MyLibA.tlb);
[
uuid(25E3CD5E-FA06-4845-BE3E-F260985AFB20),
helpstring("My CoClass")
]
coclass MyCoClass
{
[default] interface IMyInterface;
};
};
I can compile the above ok, but when I open the tlb file generated by MIDL in oleview, I get an error message TYPE_E_CANTLOADLIBRARY. I'm beginning to suspect what I want to do is not possible. My experimentation so far suggests that type libraries need to contain all the interfaces that a coclass implements along with the coclass definition itself. Is this true?
If I remove the importlib("MyLibA.tlb); statement, I can view the compiled tlb file in oleview without errors, but MyLibB.tlb then also contains the definition of the IMyInterface interface, i.e. the interface is defined twice in both type libraries. I don't want this because in my application I load both a.dll and b.dll using registration-free COM. In this scenario, the activation context generation fails when it encounters the same interface definition in more than one type library.
Any suggestions how I can achieve the desired interface and coclass separation in separate type libraries?
When OLE/COM viewer shows the TYPE_E_CANTLOADLIBRARY this typically means that another TLB which is referenced from the one which is being opened is not properly registered.
The fix is to register the dependency TLB (in this case MyLibA.tlb) with a tool like regtlb or regtlib or alternative, depending on your system.
As the question is given in the context of registration-free COM, you should be aware of possible issue with regard to marshaling of the interface instances. Typically, TLBs must be registered in order to use standard marshaller. Otherwise, you must make sure to properly declare marshaling info in your manifests, as mentioned here

IoC/DI - Implementation in internal class having only internal methods

We are implementing IoC/DI in our application using NInject framework. We are having internal classes having internal methods. To implement IoC/DI, we have to extract interfaces. But if we are having only internal methods in an internal class, we can't extract interface for that class.
So is there a way to implement IoC/DI in such cases (internal class having only internal methods) or should we change our internal methods to public methods. Kindly suggest. Thanks
If your class is already internal then there is absolutely not difference between internal and public methods. public methods of internal classes are only internally visible.
If you stay with injecting concrete classes though you loose all the advantages of DI. So yes you should extract (internal) interfaces and inject the interfaces. This requires that the configuration code has access to the classes by either beeing in the same assembly of the assembly must be declased as friend assembly. Futhermore, you have to configure Ninject to allow none public classes. See NinjectSettings.
The only thing that you really need to make public is the interface (not the concrete implementation).
You can use an abstract factory or (easier) Ninject to map the public interface to the internal concrete; thus your client code just has to request an instance of "a thing" that implements the interface and your factory / container will return the implementation.
You should read up on Dependency Inversion Principle as well as it goes hand-in-hand with this.
You could use InternalsVisibleTo attribute in AssemblyInfo.cs file like this
[assembly: InternalsVisibleTo("Assembly_That_Should_Access_The_Internal_Class")]

What's the purpose of noncreatable coclasses in IDL?

What is the reason for declaring noncreatable coclasses like the following in IDL?
[
uuid(uuidhere),
noncreatable
]
coclass CoClass {
[default] interface ICoClass;
};
I mean such class will not be registered to COM anyway. What's the reason to mention it in the IDL file and in the type library produced by compiling that IDL file?
noncreatable is good when you want to stop clients from instantiating the object with the default class factory yet still have a proper CLSID for logging, debugging &c; see an example at http://www.eggheadcafe.com/software/aspnet/29555436/noncreatable-atl-object.aspx of an issue which is properly resolved that way.
The noncreatable attribute is just a hint to the consumer of the object -- .Net and VB6, for example, when seeing this attribute, will not allow the client to create the object "the normal way", e.g. by calling New CoClass() [VB6].
However, the COM server's class factory is the definite authority for deciding whether it allows objects of given class to be created or not -- so in fact, it is possible that a class is marked noncreatable and yet, the class factory allows objects to be created. To avoid such situations, make sure that you update your class factory accordingly.
Mentioning noncreatable classes in the IDL is in fact optional. Note, however, that you get at least one benefit from including them anyway: midl will create CLSID_CoClass constants etc.

Dependency Injection and Circular reference

I am just starting out with DI & unit testing and have hit a snag which I am sure is a no brainer for those more experienced devs :
I have a class called MessageManager which receives data and saves it to a db. Within the same assembly (project in Visual Studio) I have created a repository interface with all the methods needed to access the db.
The concrete implementation of this interface is in a separate assembly called DataAccess.
So DataAccess needs a project reference to MessageManager to know about the repository interface.
And MessageManager needs a project reference to DataAccess so that the client of MessageManager can inject a concrete implementation of the repository interface.
This is of courser not allowed
I could move the interface into the data access assembly but I believe the repository interface is meant to reside in the same assembly as the client that uses it
So what have I done wrong?
You should separate your interface out of either assembly. Putting the interface along with the consumer or the implementor defeats the purpose of having the interface.
The purpose of the interface is to allow you to inject any object that implements that interface, whether or not it's the same assembly that your DataAccess object belongs to. On the other hand you need to allow MessageManager to consume that interface without the need to consume any concrete implementation.
Put your interface in another project, and problem is solved.
You only have two choices: add an assembly to hold the interface or move the interface into the DataAccess assembly. Even if you're developing an architecture where the DataAccess class may someday be replaced by another implementor (even in another assembly) of the repository interface, there's no reason to exclude it from the DataAccess assembly.
Are you using an Inversion of Control Container? If so, the answer is simple.
Assembly A contains:
MessageManager
IRepository
ContainerA (add MessageManager)
Assembly B contains (and ref's AssemblyA):
Repository implements IRepository
ContainerB extends ContainerA (add Repository)
Assembly C (or B) would start the app/ask the container for MessageManager which would know how to resolve MessageManager and the IRepository.
I think you should move the repository interface over to the DataAccess assembly. Then DataAccess has no need to reference MessageManager anymore.
However, it remains hard to say since I know next to nothing about your architecture...
Frequently you can solve circular reference issues by using setter injection instead of constructor injection.
In pseudo-code:
Foo f = new Foo();
Bar b = new Bar();
f.setBar(b);
b.setFoo(f);
Dependency inversion is in play:
High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.
The abstraction that the classes in the DatAccess assembly depend upon needs to be in a separate assembly from the DataAccess classes and the concrete implementation of that abstration (MessageManager).
Yes that is more assemblies. Personally that's not a big deal for me. I don't see a big downside in extra assemblies.
You could leave the structure as you currently have it (without the dependency from MessageManager to DataAccess that causes the problem) and then have MessageManager dynamically load the concrete implementation required at runtime using the System.Reflection.Assembly class.