First of all: I'm total beginner.in COM.
I'm working in team on big project. The server part is written in C++. The client side is written in C#. They communicate through COM.
Now - I have interface IA in C#. And I have object o, whose type is class A (implements IA in C++ - it is somehow trasfered via COM). I want to use reflection to get all properties of that type, but it's not working properly. It returns just those properties, which I have used in my code.
Here is the Reflection code that retrieves the properties:
Type[] ifaces = typeof(A).GetIterfaces();
foreach (Type iface in ifaces)
{
foreach (PropertyInfo info in iface.GetProperties())
{
// it takes only those properties, I have used in C# code
}
}
First I thought it's not working because of COM. But it's weird, that it gives me all properties, which I mention in code. And all stuff around COM should be written correctly, because it's working for a long time (before I got to this project).
This might help you: Using Reflection with COM Interop
This would help only if you know possible options for the property name, if you have no idea but want to list them, you might have to dive into the tlb file. Good example on how to load a typelib and get the AssemblyBuilder class you can find here. AssemblyBuilder.GetExportedTypes method should return all types defined in TLB, and then you can use reflection on those types.
I have been struggling with this, so if you get it working, maybe you could post a solution here.
The problem was in Embed interop types. I switched from True to False and it's working.
Related
I have written several pure .NET DirectShow filters (they are transform filters) and registered them via regasm. GraphStudioNext has no problems using them.
My problem is when my C# app tries to use the filters -- I have to get .NET to instantiate the COM object as a COM object and not a managed dotnet object. This is because I've implemented a filter selection utility (like GraphStudioNext's insert filter from a list feature) and I can't add a reference to the assembly at compile time -- someone could write a custom .NET DirectShow filter with their own ComImport'ed IBaseFilter. This will cause problems when my code tries to cast the type to IBaseFilter even though their IBaseFilter and my IBaseFilter share the same Guid. As a COM object, this would be no problem. As a .NET object, they're actually different types.
Say one inteded to write GraphStudioNext in C# and have it work with pure .NET DirectShow filters -- is this even possible?
A good question. I dealt with a somewhat similar problem here. Indeed, [ComImport] interface type equivalency doesn't work when you deal with a native .NET object directly. You need to hide the .NET object behind an artificial COM proxy for the COM interface equivalency to work.
In the solution to my question, I initially used ICustomQueryInterface and Marshal.CreateAggregatedObject to aggregate the .NET object, to expose it as COM object for that reason.
Later, I ended up implementing my own IUnknown runtime stub (using Marshal.GetFunctionPointerForDelegate for AddRef, Release and QueryInterface), which I used as pOuter (the controlling IUnknown) object for CreateAggregatedObject, so it didn't violate COM identity rules. That was hack-ish, but it solved the problem for me.
If the filter is registered in the system and you know the CLSID of it, then you can use:
Type filterType = Type.GetTypeFromCLSID(filterClsid);
var filter = (IBaseFilter)Activator.CreateInstance(filterType);
If the filter is not registered in the system, but you know the dll-location and the CLSID, you can do it like in C++. You need some P/Invokes for it! Call LoadLibraryEx and then get the IClassFactory. With this you can IClassFactory::CreateInstance of your filter.
I know this works, because we have done it and we are only using this method to work with custom directshow filters.
I've got a .dll library I'm writing that interfaces with a proprietary COM assembly. My goal is to publish my work online once it's built, however I need to remove the COM assembly as a project reference to avoid distribution of this proprietary dll. So what I'm trying to be able to do is dynamically load the assembly at runtime, and invoke methods where I need them. Traditionally I've used object reflection for unknown types, however this can get slow at times, and involves several ugly instanciations. In .NET 4.0 is there a way to cleanly get all the methods and toss them into a dynamic class/interface at runtime?
I'm currently getting the object like this:
Type myClassType = Type.GetTypeFromProgID("MyClass.Myclass.1");
object classObj = Activator.CreateInstance(myClassType);
I thought I'd be able to use Type.GetMethods(), however it only returns the generic ones (Equals, ToString, GetLifetime..., etc.). I know the class uses an interface, so I tried looking into dynamically loading the interface also. That led me to Reflection.Emit, and the Microsoft.Xrm.Sdk, which I am failing to understand so far.
If there's a way for me to invoke methods without needing to throw a bunch of BindingFlags every few lines, I'd greatly appreciate a nudge in the right direction
I do have the GUID for both the Class and the Interface if that helps at all.
If I were at your situation(and if i have understand the problem correctly):
I would separate the Interface,s library (DLL) from implementation library(DLL)
Then the implementation library would be loaded dynamically and my main source code that is
referenced to Interface library would be complied
Type myClassType = Type.GetTypeFromProgID("MyClass.Myclass.1");
myClassIntrface classObj =
Activator.CreateInstance(myClassType) as myClassIntrface;
classObj.CallSomeInterfaceMethod();
hope this will be useful pal.
How can I read out all property names via reflection of an COM Object in C#?
I know how to get the property if I know the name.
comObject.GetType().InvokeMember("PropertyName", System.Reflection.BindingFlags.GetProperty, null, comObject, null);
but what is when I want to dump all properties?
PropertyInfo[] properties = t.GetProperties();
This way didn't work with Com-Objects. If I do a GetMembers() I get these Members:
Name: GetLifetimeService
Name: InitializeLifetimeService
Name: CreateObjRef
Name: ToString
Name: Equals
Name: GetHashCode
Name: GetType
regards Chris
You got the members of the __ComObject class, the underlying .NET class for an RCW.
COM has a wee bit support for reflection, as long as the COM coclass implements IDispatch, the Automation interface. Not unusual, it is the interface that scripting languages use to make calls. IDispatch.GetIDsOfNames() is always implemented, but you have to know the name of the member up front. IDispatch.GetTypeInfo() gives access to the type library for the coclass, but isn't always implemented. Translation of type library info to metadata is an imperfect art, the core reason why .NET wants you to do this upfront with Tlbimp.exe. If you want to pursue a runtime approach then you'll probably benefit from the source for the managed version of Tlbimp, available here.
Doing this up front at build time is always best, you do so by adding a reference to the type library (usually embedded in the executable file) or by running Tlbimp.exe yourself. Now you got a .NET interop wrapper class that has all of the members of the underlying COM coclass and interfaces. At which point you probably don't need reflection anymore :)
I've just published a CodeProject article about how to do Reflection with IDispatch-based COM objects. The article provides a small C# DispatchUtility helper class that's easy to include in other projects. Internally, it uses a custom declaration of IDispatch and .NET's TypeToTypeInfoMarshaler to convert IDispatch's ITypeInfo into a rich .NET Type instance.
In your example, you could call DispatchUtility.GetType(comObject, true) to get back a .NET Type instance, which you could then call GetProperties or GetMembers on.
I've also provided a version of the DispatchUtility source code on StackOverflow in a response to How to enumerate members of COM object in C#?
I've got a tiny (I hope) problem again, and I don't know how to obtain access to some presentation properties provided by PowerPoint (however I don't even know how to google it or search it at the site :( ) from C#. Let me explain. We can access a TextRange property both in C# and VBA, via an interop assembly and ms-office-built-in VBA editor respectively. It's ok, but this property contains two same-named entities - Runs. VBA allows to access it as a method and as a property (moreover, Runs property object insides are useful), but the property Runs in not accessible via the interop assembly, Runs() method can be accessed only (and it returns text run objects). I've digged in the interop assembly using .NET Reflector but I have not found anything related to the Runs property (though properties with different unique rather than methods names have own get_Property() and set_Property() methods). It seems that the interop assembly is missing the Runs property for TextRange interface. Frankly, I'm not sure. :(
Can I somehow obtain the access Runs property from C#? I'm not familiar with COM, etc, and I hope for your help. Thanks.
I think you are talking about the Microsoft.Office.Core.TextRange2.Runs() property. It is a property that takes two arguments, start and length. Such a property is not directly accessible in the C# language, at least not until C# 4.0. Only Visual Basic supports indexed properties right now.
The workaround is to use get_Runs() instead.
In C# you have to specify where to start and where to end:
...
foreach (TextRange txtrn in txtrng.Runs(0, txtrng.Length))
{
if(txtrn.Font.Name =="Arial")
MessageBox.Show(txtrn.Text);
}
.....
I'm trying to wrap my head around reflection, so I decided to add plugin capability to a program that I'm writing. The only way to understand a concept is to get your fingers dirty and write the code, so I went the route of creating a simple interface library consisting of the IPlugin and IHost interfaces, a plugin implementation library of classes that implement IPlugin, and a simple console project that instantiates the IHost implementation class that does simple work with the plugin objects.
Using reflection, I wanted to iterate through the types contained inside my plugin implementation dll and create instances of types. I was able to sucessfully instantiate classes with this code, but I could not cast the created object to the interface.
I tried this code but I couldn't cast object o as I expected. I stepped through the process with the debugger and the proper constructor was called. Quickwatching object o showed me that it had the fields and properties that I expected to see in the implementation class.
loop through assemblies
loop through types in assembly
// Filter out unwanted types
if (!type.IsClass || type.IsNotPublic || type.IsAbstract )
continue;
// This successfully created the right object
object o = Activator.CreateInstance(type);
// This threw an Invalid Cast Exception or returned null for an "as" cast
// even though the object implemented IPlugin
IPlugin i = (IPlugin) o;
I made the code work with this.
using System.Runtime.Remoting;
ObjectHandle oh = Activator.CreateInstance(assembly.FullName, type.FullName);
// This worked as I intended
IPlugin i = (IPlugin) oh.Unwrap();
i.DoStuff();
Here are my questions:
Activator.CreateInstance(Type t) returns an object, but I couldn't cast the object to an interface that the object implemented. Why?
Should I have been using a different overload of CreateInstance()?
What are the reflection related tips and tricks?
Is there some crucial part of reflection that I'm just not getting?
I'm just guessing here because from your code it's not obvious where do you have definition of IPlugin interface but if you can't cast in your host application then you are probably having IPlugin interface in your host assembly and then at the same time in your plugin assembly. This won't work.
The easiest thing is to make this work is to have IPlugin interface marked as public in your host assembly and then have your Plugin assembly reference host application assembly, so both assemblies have access to the very same interface.
hmmm... If you are using Assembly.LoadFrom to load your assembly try changing it Assembly.LoadFile instead.
Worked for me
From here: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx
#lubos hasko
You nailed it on the nose. My original design did have three different assemblies with both the host and plugin implementation referencing the plugin interface assembly.
I tried a separate solution with a host implementation and interface assembly and a plugin implementation assembly. Within that solution, the code in the first block worked as expected.
You've given me a bit more to think about, because I'm not quite understanding why two assemblies referencing a common assembly don't get the same type out of the common assembly.
I was just trying to work this out myself and managed to stumble on the answer!
I had 3 different C# projects
A - Plugin Interface project
B - Host exe project -> references A
C - Plugin Implementation project -> references A
I was getting the casting error as well until I changed the assembly name for my Plugin Interface proj to match the namespace of what I was trying to cast to.
E.g.
IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);
was failing because the assembly that the IPluginModule interface was defined in was called 'Common', The -type- I was casting to was 'Blah.Plugins.Common.IPluginModule' however.
I changed the Assembly name for the interface proj to be 'Blah.Plugins.Common' meant that the cast then succeeded.
Hopefully this explanation helps someone. Back to the code..
Is your type not public, if so, call the overload that takes in a boolean:
Activator.CreateInstance(type, true);
Also, in your first example, see if o is null and if not, print out o.GetType().Name to see what it really is.
#Haacked
I tried to keep the pseudocode simple. foreach's take up a lot of space and braces. I clarified it.
o.GetType().FullName returns Plugins.Multiply which is the expected object. Plugins.Multiply implements IPlugin. I stepped through the process in the debugger quite a few times until I gave up for the evening. Couldn't figure out why I couldn't cast it because I watched the constructor fire until I got grumpy about the whole mess. Came back to it this evening and made it work, but I still don't understand why the cast failed in the first code block. The second code block works, but it feels off to me.
The link to egghead above is the main solution to the problem use Assembly.LoadFile() instead of .LoadFrom()