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.
Related
I have the following code working in a SpringBoot application, and it does what's I'm expecting.
TypePool typePool = TypePool.Default.ofClassPath();
ByteBuddyAgent.install();
new ByteBuddy()
.rebase(typePool.describe("com.foo.Bar").resolve(), ClassFileLocator.ForClassLoader.ofClassPath())
.implement(typePool.describe("com.foo.SomeInterface").resolve())
.make()
.load(ClassLoader.getSystemClassLoader());
Its makes is so that the class com.foo.Bar implements the interface com.foo.SomeInterface (which has a default implementation)
I would like to . use the above code by referring to the class as Bar.class, not using the string representation of the name. But if I do that I get the following exception.
java.lang.UnsupportedOperationException: class redefinition failed: attempted to change superclass or interfaces
I believe due to the fact that it cause the class to be loaded, prior to the redefinition. I'm just now learning to use ByteBuddy.
I want to avoid some reflection at runtime, by adding the interface and an implementation using ByteBuddy. I've some other code that checks for this interface.
This is impossible, not because of Byte Buddy but no tool is allowed to do this on a regular VM. (There is the so-called dynamic code evolution VM which is capable of that).
If you want to avoid the problem, use redefine rather then rebase. Whenever you instrument a method, you do now however replace the original.
If this is not acceptable, have a look at the Advice class which you can use by the .visit-API to wrap logic around your original code without replacing it.
I'm trying to solve the problem of serializing and deserializing Box<SomeTrait>. I know that in the case of a closed type hierarchy, the recommended way is to use an enum and there are no issues with their serialization, but in my case using enums is an inappropriate solution.
At first I tried to use Serde as it is the de-facto Rust serialization mechanism. Serde is capable of serializing Box<X> but not in the case when X is a trait. The Serialize trait can’t be implemented for trait objects because it has generic methods. This particular issue can be solved by using erased-serde so serialization of Box<SomeTrait> can work.
The main problem is deserialization. To deserialize polymorphic type you need to have some type marker in serialized data. This marker should be deserialized first and after that used to dynamically get the function that will return Box<SomeTrait>.
std::any::TypeId could be used as a marker type, but the main problem is how to dynamically get the deserialization function. I do not consider the option of registering a function for each polymorphic type that should be called manually during application initialization.
I know two possible ways to do it:
Languages that have runtime reflection like C# can use it to get
deserialization method.
In C++, the cereal library uses magic of static objects to register deserializer in a static map at the library initialization time.
But neither of these options is available in Rust. How can deserialization of polymorphic objects be added in Rust if at all?
This has been implemented by dtolnay.
The concept is quite clever ans is explained in the README:
How does it work?
We use the inventory crate to produce a registry of impls of your trait, which is built on the ctor crate to hook up initialization functions that insert into the registry. The first Box<dyn Trait> deserialization will perform the work of iterating the registry and building a map of tags to deserialization functions. Subsequent deserializations find the right deserialization function in that map. The erased-serde crate is also involved, to do this all in a way that does not break object safety.
To summarize, every implementation of the trait declared as [de]serializable is registered at compile-time, and this is resolved at runtime in case of [de]serialization of a trait object.
All your libraries could provide a registration routine, guarded by std::sync::Once, that register some identifier into a common static mut, but obviously your program must call them all.
I've no idea if TypeId yields consistent values across recompiles with different dependencies.
A library to do this should be possible. To create such a library, we would create a bidirectional mapping from TypeId to type name before using the library, and then use that for serialization/deserialization with a type marker. It would be possible to have a function for registering types that are not owned by your package, and to provide a macro annotation that automatically does this for types declared in your package.
If there's a way to access a type ID in a macro, that would be a good way to instrument the mapping between TypeId and type name at compile time rather than runtime.
Two simple COM IDL file questions I can't seem to find answers for, even with searching MSDN and the general internet:
Is there an interface attribute which lets me specify my interface is to be implemented by STA objects only, or is this a detail for my documentation alone? I already have [object, local] which I think is correct for non-remoting (in-process) COM objects.
Do I need void in the parentheses of my method declarations (like in C) to specify no arguments? MSDN is inconsistent about this; so are header files. My own personal implementations of this interface will be in C.
Thanks.
You are talking about the threading model you want to specify for your COM component. No, you cannot put that in the IDL, it is far too important. A client doesn't have to use your IDL, a scripting language like Javascript never will for example. It must go in the registry, in the CLSID key for your component. You want ThreadingModel = "Apartment" to request the client to provide an STA thread. If it is missing then COM assumes that by default.
Do keep in mind that this does not force the client programmer to provide one. If he favors MTA for some reason then COM will provide the STA thread to give your component as safe home. If your proxy makes it too slow to be usable then you do have a documentation requirement.
No HRESULT Method(void) in the IDL is not necessary, using HRESULT Method() is sufficient. Midl.exe doesn't care what language you use.
MSDN:
"You implement an IClassFactory interface for each (COM) class of object that you offer to be instantiated."
Is it useful to create COM class without Class Factory?
The IClassFactory is provided for objects which are instantiated directly by the caller, for example using CreateObject or CoCreateInstance, or GetObject.
Other objects can be obtained by getting them indirectly from objects that are created.
For example, the Scripting.FileSystemObject in VB or VBScript is created directly. You can use the methods to obtain File or Folder objects, which cannot be directly created. Instead these are created by the FileSystemObject and returned from FileSystemObject methods.
Is it useful to create COM class without Class Factory?
Yes, why not? It can still be fully featured COM class, just except that you cannot launch it via CoCreateInstance API. For some reason you might want to make it available otherwise, e.g. as a returned [out] parameter on a method of another interface/class, or via GetActiveObject API.
Class factories let you expose your class for direct instantiation.
I'm not entirely sure the wording is quite correct here. You almost always implement IClassFactory once for all COM classes of objects that your host will instantiate. In particular, your implementation of IClassFactory is what gets returned from DllGetClassObject.
In particular, when someone calls CoCreateInstance(CLSID_foo, pUnkOuter, CLSCTX_INPROC, IID_IFoo, (void **) &pFoo), the following things happen (assuming you're not doing remoting):
COM looks up CLSID_foo in the registry. (In particular, HKEY_CLASSES_ROOT\CLSID\\InprocServer32).
COM loads that DLL and calls DllGetClassObject with IID_IClassFactory.
Your DLL returns a function pointer to the implementation of IClassFactory.
COM calls your implementation of IClassFactory::CreateInstance with pUnkOuter, IID_IFoo, and pFoo.
There are many other situations where you would have COM objects that aren't directly creatable, as #Ben mentioned. There are even other standard factory interfaces, like IServiceProvider, that exist so that classes can expose a dynamic set of interfaces.
I want to be able to define in my web.config the type of connexion my object will use to get data (variable) (from an xml or from a databases).
I though about using a Strategie Pattern, but I'm somewhat stuck by the need to write somewhere the name of the class, which I do not want.
Any suggestions?
Additionnal info
I have the interface IContext.
It's implemented in ContextXML and ContextDB.
I have the class Context which has a IContext member (called _context).
The Context class reads (through ContextConfiguration) app.config.
I want _context to be able to be a ContextXML or a ContextDB... or a ContextJSon or any other new class that would implements IContext.
Have you thought about creating a ContextManager class and employing "configuration by convention"?
What I would do, is add a member getName to your IContext interface - this just returns a nice human-readable string for each implementation - as simple as "ContextXML" for your ContextXML class.
When your ContextManager (probably a Singleton, BTW) starts up, it scans a known directory for IContext implementations, instantiating them by reflection (or some other mechanism, I'm not familiar with VB.Net but I'm sure there's a way), and placing them in a collection.
Now when you are building up Context objects, you can ask your ContextManager for a suitable IContext - either explicitly [e.g. getIContextByName("ContextDB")] or with a simpler method that just returns whatever has been configured by some other mechanism - i.e. a suite of methods something like this:
getPossibleIContextImplementationNames()
setCurrentIContextImplementation({name})
getCurrentIContext()
Just as an aside, are you stuck with that naming? Because having a Context object that uses an IContext seems a little unusual. If your IContext implementations are actually used to retrieve data from somewhere, why not call the interface IDAO or IDataAccessor?