Classes declared dynamically with GuidAttribute - c#

I have a t4 template that creates many classes based on a database table. These classes need to be exposed to COM, so they are declared with the GuidAttribute attribute.
Whenever I compile the project, say to test something and register it in the test environment, new GUIDs are created for each class definition, and I'm starting to worry that I may be doing bad things to the Windows Registry...
If I compile the project and I have the definition of Class1 like
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[GuidAttribute("AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA")]
public class Class1
{
...
}
And tomorrow I want to test something else and Class1 now looks like
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[GuidAttribute("BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB")]
public class Class1
{
...
}
Will the previous GUID remain in the registry, or is the registration process smart enough to remove everything from the previous registration?
This whole question may come from my ignorance of what are these GUIDs used for and how they relate to CLSIDs, but the fact that they are meant to be declared statically with the class definition, and I'm doing it dynamically makes me somewhat uneasy.

Will the previous GUID remain in the registry
If you don't explicitly unregister the component, yes. Easy to forget of course. You have to run Regasm.exe /uninstall from an elevated command prompt.
is the registration process smart enough to remove everything
Depends how you register. If you let MSBuild do it (Project + Properties, Build tab, Register for COM interop option) then it will automatically unregister the server before rebuilding the DLL. But since you use [Guid], it immediately writes it back of course :) Net effect is zero. If you do it by hand by running Regasm.exe then no unregistration takes place.
Do keep in mind that [Guid] is sacred in COM. Explicitly specifying like you do is quite risky, there is a rock-hard rule in COM that you must change the guid when you change the declaration. Not doing so causes very nasty DLL Hell problems. Using the [Guid] attribute is only reasonable when you have to write a replacement for an existing COM server. Or to avoid registry pollution when you don't let MSBuild clean up or want to avoid a client programming tool hassling you with constantly having to re-select the type library. But then it is very important that you remove the attribute again when you are done testing. Easy to forget of course :)

Related

How to control the generated interface GUID of a COM interface generated with AutoDual

My problem is that I have a .NET project with like 100+ classes visible to COM. Classes are published to COM using the AutoDual attribute on the class. My problem is that I would like to let the compiler auto generate the COM Interface (hence this AutoDual) BUT I would like to be able to specify the GUID for the generated interface.
The goal is to make sure that small changes like:
adding a method
modifying a method that is not being used by a specific client
increasing the version number of my DLL
won't break the clients (those using early binding) and force them to recompile.
I know (read here: Why should I not use AutoDual?) that a solution for that would be to create the 100+ interfaces manually and give them a GUID and DispId for each method so the changes mentionned above would no longer break older clients. However, I would like to avoid actually writing those interfaces manually, and having to maintain them when new methods needs to be added in both the class and interface.
So far I have managed to "automatically" publish those classes to COM without writing COM specific code by using PostSharp to inject the following attributes:
On classes:
ComVisible(true)
ClassInterfaceType.AutoDual
GUID("A guid of my own automatically generated but invariant for a gievn class FullName")
On public methods and properties:
DispId(xx) // where xx is again a dispId generated but invariant for a given class name/method name couple.
Having done that :
the class GUID are invarriant what ever changes I make to them
the DispId are also invarriant on the generated interface
Only the Interface GUID poses problem as it varies every time a method is added.
What I now need would be a way to ensure the generated interface for a given class always has the same GUID, by either:
a specific attribute i don't know of, like 'AutoDualInterfaceGuid("My GUID") on the class
a pre compilation process to generate the interfaces, with a GUID of my choice
a post compilation process to modifiy the GUID of generated COM interfaces
a way to modify the default generation of COM Interfaces in order to place my GUID logic in there.
Any idea on how to set a specific GUID for a generated COM Interface would be much appreciated.
You'd simply use the [Guid] attribute on the interface and the class:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("{7447EEEA-3D48-4D20-80DF-739413718794}")]
public interface IFoo {
[DispId(42)] void method();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("{40815257-BFD2-43D9-9CF8-FB27CC884C71}")]
[ProgId("Acme.Foo")]
public class Foo : IFoo {
public void method() { /* etc */ }
}
And in the AssemblyInfo.cs file:
[assembly: Guid("B75B31AD-D96A-473F-94E0-37E59847B997")]
Which covers the DispId of the interface members, the IID of the interfaces, the CLSID of the coclass, the ProgId of the coclass and the LIBID of the type library.
However, I would like to avoid actually writing those interfaces
You can use ClassInterfaceType.AutoDispatch to avoid writing the interfaces but that achieves the exact opposite of what you asked for. You can no longer control the IID anymore, you'll expose the System.Object methods which gives the client a type library dependency on mscorlib.tlb and every change you make will break the client. Very convenient to you, extremely inconvenient to your clients. But read on:
the class GUID are invariant what ever changes I make to them
I showed you how to do this. But this is actually a very strong anti-pattern in COM. Which demands that you change the IID when you make changes. Not changing it causes extremely nasty problems at runtime when the change you make is breaking. Very easy to do, just inserting or removing a method or changing the return type or arguments of a method are enough. Okay when the client code late-binds through IDispatch, fatal when it early-binds. The client will call the completely wrong method. Or you'll get arbitrary garbage values for the arguments. The client will crash with an AccessViolationException when it's lucky, next to impossible to diagnose why. It is not lucky then the call succeeds but just completely fails to operate correctly, utterly impossible to diagnose.
Don't do it.

Interface change between versions - how to manage?

Here's a rather unpleasant pickle that we got into on a client site. The client has about 100 workstations, on which we deployed version 1.0.0 of our product "MyApp".
Now, one of the things the product does is it loads up an add-in (call it "MyPlugIn", which it first looks for on a central server to see if there's a newer version, and if it is then it copies that file locally, then it loads up the add-in using Assembly.Load and invokes a certain known interface. This has been working well for several months.
Then the client wanted to install v1.0.1 of our product on some machines (but not all). That came with a new and updated version of MyPlugIn.
But then came the problem. There's a shared DLL, which is referenced by both MyApp and MyPlugIn, called MyDLL, which has a method MyClass.MyMethod. Between v1.0.0 and v1.0.1, the signature of MyClass.MyMethod changed (a parameter was added). And now the new version of MyPlugIn causes the v1.0.0 client apps to crash:
Method not found: MyClass.MyMethod(System.String)
The client pointedly does not want to deploy v1.0.1 on all client stations, being that the fix that was included in v1.0.1 was necessary only for a few workstations, and there is no need to roll it out to all clients. Sadly, we are not (yet) using ClickOnce or other mass-deployment utilities, so rolling out v1.0.1 will be a painful and otherwise unnecessary exercise.
Is there some way of writing the code in MyPlugin so that it will work equally well, irrespective of whether it's dealing with MyDLL v1.0.0 or v1.0.1? Perhaps there's some way of probing for an expected interface using reflection to see if it exists, before actually calling it?
EDIT: I should also mention - we have some pretty tight QA procedures. Since v1.0.1 has been officially released by QA, we are not allowed to make any changes to MyApp or MyDLL. The only freedom of movement we have is to change MyPlugin, which is custom code written specifically for this customer.
The thing is that the changes you made have to be basically in addition and not the change. So if you want to be back compatible in your deployment (as much as I understood in current deployment strategy you have this is an only option) you should never change the interface but add a new methods to it and avoid tight linking of your plugin with shared DLL, but load it dynamically. In this case
you will add a new funcionality without disturbing a old one
you will be able to choose which version of dll to load at runtime.
I have extracted this code from an application I wrote some time ago and removed some parts.
Many things are assumed here:
Location of MyDll.dll is the current directory
The Namespace to get reflection info is "MyDll.MyClass"
The class has a constructor without parameters.
You don't expect a return value
using System.Reflection;
private void CallPluginMethod(string param)
{
// Is MyDLL.Dll in current directory ???
// Probably it's better to call Assembly.GetExecutingAssembly().Location but....
string libToCheck = Path.Combine(Environment.CurrentDirectory, "MyDLL.dll");
Assembly a = Assembly.LoadFile(libToCheck);
string typeAssembly = "MyDll.MyClass"; // Is this namespace correct ???
Type c = a.GetType(typeAssembly);
// Get all method infos for public non static methods
MethodInfo[] miList = c.GetMethods(BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
// Search the one required (could be optimized with Linq?)
foreach(MethodInfo mi in miList)
{
if(mi.Name == "MyMethod")
{
// Create a MyClass object supposing it has an empty constructor
ConstructorInfo clsConstructor = c.GetConstructor(Type.EmptyTypes);
object myClass = clsConstructor.Invoke(new object[]{});
// check how many parameters are required
if(mi.GetParameters().Length == 1)
// call the new interface
mi.Invoke(myClass, new object[]{param});
else
// call the old interface or give out an exception
mi.Invoke(myClass, null);
break;
}
}
}
What we do here:
Load dynamically the library and extract the type of MyClass.
Using the type, ask to the reflection subsystem the list of MethodInfo present in that type.
Check every method name to find the required one.
When the method is found build an instance of the type.
Get the number of parameters expected by the method.
Depending on the number of parameters call the right version using Invoke.
My team has made the same mistake you have more than once. We have a similar plugin architecture and the best advice I can give you in the long run is to change this architecture as soon as possible. This is a maintainability nightmare. The backwards compatibility matrix grows non-linearly with each release. Strict code reviews can provide some relief, but the problem is you always need to know when methods were added or changed to call them in the appropriate way. Unless both the developer and reviewer know exactly when a method was last changed you run the risk of there being a runtime exception when the method is not found. You can NEVER call a new method in MyDLL in the plugin safely, because you may run on a older client that does not have the newest MyDLL version with the methods.
For the time being, you can do something like this in MyPlugin:
static class MyClassWrapper
{
internal static void MyMethodWrapper(string name)
{
try
{
MyMethodWrapperImpl(name);
}
catch (MissingMethodException)
{
// do whatever you need to to make it work without the method.
// this may go as far as re-implementing my method.
}
}
private static void MyMethodWrapperImpl(string name)
{
MyClass.MyMethod(name);
}
}
If MyMethod is not static you can make a similar non-static wrapper.
As for long term changes, one thing you can do on your end is to give your plugins interfaces to communicate through. You cannot change the interfaces after release, but you can define new interfaces that the later versions of the plugin will use. Also, you cannot call static methods in MyDLL from MyPlugIn. If you can change things at the server level (I realize this may be outside your control), another option is to provide some sort of versioning support so that a new plugin can declare it doesn't work with an old client. Then the old client will only download the old version from the server, while newer clients download the new version.
Actually, it sounds like a bad idea to change the contract between releases. Being in an object-oriented environment, you should rather create a new contract, possibly inheriting from the old one.
public interface MyServiceV1 { }
public interface MyServiceV2 { }
Internally you make your engine to use the new interface and you provide an adapter to translate old objects to the new interface.
public class V1ToV2Adapter : MyServiceV2 {
public V1ToV2Adapter( MyServiceV1 ) { ... }
}
Upon loading an assembly, you scan it and:
when you find a class implementing the new interface, you use it directly
when you find a class implementing the old interface, you use the adapter over it
Using hacks (like testing the interface) will sooner or later bite you or anyone else using the contract - details of the hack have to be known to anyone relying on the interface which sounds terrible from the object-oriented perspective.
In MyDLL 1.0.1, deprecate the old MyClass.MyMethod(System.String)and overload it with the new version.
Could you overload MyMethod to accept MyMethod(string) ( version 1.0.0 compatible) and MyMethod(string, string) (v1.0.1 version)?
Given the circumstances, I think the only thing you can do really is have two versions of MyDLL running 'side by side',
and that means something like what Tigran suggested, loading the MyDLL dynamically - e.g. as an a side example not related but might help you, take a look at the the RedemptionLoader http://www.dimastr.com/redemption/security.htm#redemptionloader (that's for an Outlook plugins which often have problems crashing to each other referencing different versions of a helper dll, just as a background story - that's a bit more complex cause of the COM involved but doesn't change much here) -
it's what you can do, something similar. Load dynamically the dll by it's location, name - you can specify that location internally, hard-code, or even set it up from config or something (or check and do that if you see that MyDll is not of the right version),
and then 'wrap' the objects, calls form the dynamically loaded dll to match what you normally have - or do some trick like that (you'd have to wrap something or 'fork' on the implementation) to make everything work in both cases.
Also to add on the 'no-nos' and your QA sorrows :),
they should not break the backward compatibility from 1.0.0 to 1.0.1 - those are (usually) the minor changes, fixes - not breaking changes, major version # is needed for that.

C++ calling C# COM interop error: HRESULT 0x80131509

I create a C# COM interop for c++ to invoke.
I have registered the dll and tlb file by regasm.
everything goes well till one day i changed code of C# part (i didn't change the definition of interface, just implementation changed). one interface in COM returns an error 0x80131509. the strange thing is, it is only happened in some computers (my develop PC is works well so i can't debug this problem).
I'm not really clear on how the C# COM worked with C++, after i registered them, i just know they create key value in window registry.(like what regasm /regfile generated). how c++ knows where the COM dll is(search path environment variables)? and what the use of tlb file in run time?
any suggestion?
I got the same error as soon as I introduced a simple inheritance hierarchy to my COM library. A quick resolution was to set the ComVisible attribute to true on the base class. This fixed my problem immediately.
It does make a lot of sense when you think about it - the compiler doesn't allow you to build a hierarchy where the base class is less visible than the inheriting class. So it being the same for COM should come as no surprise - the only difference being, that it is failing at run-time instead of compile-time.
I would venture that the true reason for the error is a broken constructor chain, but I put no further research into it.
I think that your problem is related to the registry... You should try to unregister and register (using regasm) your dll in the computers that are having this problem.
If that doesn't work unregister the dll in those computers, than use regedit to search and delete any missing registry keys that refer to it, after that register your dll again. You could also use one of those registry cleaner programs after deleting the missing keys to guarantee that you didn't miss anything.
Remember that you should allways register a dll in the directory that it will be used by your application and this should happen only once. If you need to unregister a dll, then you should allways do it in the same directory that you used for the registration. In other words, once a dll is registered do not move it.
Note: if your dll is not on the same path as your C++ application it should be in a directory that is referenced in the PATH environment variable.
I got the same error message when I was calling a .Net4 C# COM object from Visual FoxPro.
The method returns object, type of which may be one of several. All the types are derived from an abstract class which implemented an interface with the common stuff for these types.
Eventually I decided to remove the abstract-modifier from the base class and just make it public and ComVisible. This solved the problem for me, even though I would like the base class to be abstract.

In C# (VS-2010), is there a way to fail a frontend build if a certain library class is used? (When normally it would compile just fine?)

I'm writing a library that has a bunch of classes in it which are intended to be used by multiple frontends (some frontends share the same classes). For each frontend, I am keeping a hand edited list of which classes (of a particular namespace) it uses. If the frontend tries to use a class that is not in this list, there will be runtime errors. My goal is to move these errors to compile time.
If any of you are curious, these are 'mapped' nhibernate classes. I'm trying to restrict which frontend can use what so that there is less spin up time, and just for my own sanity. There's going to be hundreds of these things eventually, and it will be really nice if there's a list somewhere that tells me which frontends use what that I'm forced to maintain. I can't seem to get away with making subclasses to be used by each frontend and I can't use any wrapper classes... just take that as a given please!
Ideally, I want visual studio to underline red the offending classes if someone dares to try and use them, with a nice custom error in the errors window. I also want them GONE from the intellisense windows. Is it possible to customize a project to do these things?
I'm also open to using a pre-build program to analyze the code for these sorts of things, although this would not be as nice. Does anyone know of tools that do this?
Thanks
Isaac
Let's say that you have a set of classes F. You want these classes to be visible only to a certain assembly A. Then you segregate these classes in F into a separate assembly and mark them as internal and set the InternalsVisibleTo on that assembly to true for this certain assembly A.
If you try to use these classes from any assembly A' that is not marked as InternalsVisibleTo from the assembly containing F, then you will get a compile-time error if you try to use any class from F in A'.
I also want them GONE from the intellisense windows. Is it possible to customize a project to do these things?
That happens with the solution I presented above as well. They are internal to the assembly containing F and not visible from any assembly A' not marked as InternalsVisibleTo in the assembly containing F.
However, I generally find that InternalsVisibleTo is a code smell (not always, just often).
You should club your classes into separate dlls / projects and only provide access to those dlls to front end projects that are 'appropriate' for it. This should be simple if your front-end and the group of classes it may use are logically related.
If not then I would say some thing smells fishy - probably your class design / approach needs a revisit.
I think you'll want to take a look at the ObsoleteAttribute: http://msdn.microsoft.com/en-us/library/system.obsoleteattribute%28v=VS.100%29.aspx
I believe you can set IsError to true and it will issue an error on build time.
(not positive though)
As for the intellisense you can use EditorBrowseableAttribute: http://msdn.microsoft.com/en-us/library/system.componentmodel.editorbrowsableattribute.aspx Or at least that is what seems to get decorated when I add a service reference and cannot see the members.

C#: Regasm generating registry entries for every class in my COM DLL?

I'm writing a class-library (IE BHO) in C# and currently wrangling with the large volume of what I think is junk output coming from REGASM's generated registry keys.
The short version is this: I only want to expose a handful of classes (currently: ONE class) to IE (and the rest of COM). Only one class has the ClassInterfaceAttribute and GUID stuff set, and I can test that the add-on only requires the COM registry keys for this class -- and yet, REGASM generates GUIDs and registry keys for every class in the entire project.
This is annoying and somewhat disturbing as I do not want my class names sitting in users' registry unless they absolutely have to be there.
To be fair, many of those other classes are marked public because I use them in a driver app from another project in the same solution, to work around IE's debugging black hole...
I'm still very green to COM in general (especially relating to .Net) and I was wondering what is the best way to hide all my other classes from regasm? Or, at least, why these classes that -- even though they are marked public -- are showing up when I haven't set any of the COM flags for them?
Thanks!
Use internal access modifier for stuff that doesn't need to have public modifier. For stuff that really needs public access use ComVisible attribute to partially hide it.
For example:
[ComVisible(false)]
public class ClassToHide {
//whatever
};
public class ClassToExpose {
public void MethodToExpose() {}
[ComVisible(false)]
public void MethodToHide() {}
};
All public member functions and member variables of all public classes are COM-visible by default. So first think of making them internal and if you really need them public hide them from COM with ComVisible.
Try using the /regfile switch - this will output a reg file rather than directly writing all your class names to the registry.
When you have the .reg file you can remove any entries you dont want to be added to the target systems registry, and deploy only those values to the target machine. Depending on how you choose to deploy your software, this might be easier and you would not have to change the code for any of your types.
In fact if you dont have access to the sourcecode, this would be the only way to achieve this.
I wrote a COM component with the same problems.
I separated all the non-COM functions into a separate helper DLL. The COM DLL only contains the code that needs to be registered. Everything else is accessed through the helper DLL.
I found that an easy way to make sure that future code wouldn't accidentally be marked as public rather than internal and show up in the registry.
Set ComVisible attribute to false in AssemblyInfo file and set apply ComVisible for only the desired classes.

Categories

Resources