I'm quite struggling when trying to to what follows.
I'm currently using an ActiveX, through an interop dll generated by Visual Studio (more precisely tlbimp, implicitly).
Different versions of this ActiveX exist, that sometimes add, remove, properties in the interfaces. If I want to change the version, I have to change the reference, recompile and so on.
I'd like to have a single version of my code. I remember that to drive Word for example, one can instantiate a word object via CreateInstance on Word.Application, and call methods, whatever the version. Calls being linked only at runtime. I'd like to do the same with the activeX I use, but I don't really know how to do that (btw, it's sage objets100c dll). I don't find it in the list of ActiveX, thus I'm not even sure I can do like for Word.Application.
Has someone a clue about how I could do that ? (might be a completely different solution, as my need is: having one code with no need to recompile).
Thank you in advance
If you have a corresponding *.tlb file, reference this one, not the dll. In the properties window of the reference, you can set the Specific Version property to False and EmbedInterop Types to True (makes it more stable).
If this does not help, you can try to create and access the object dynamically instead of adding a reference. You need either the ProgID of the COM type …
Type comType = Type.GetTypeFromProgID("MyProg.ProgId");
… or the CLSID of the COM type (you may find them in the registry)
Type comType = Type.GetTypeFromCLSID(new Guid("EA2BACD6-9D0F-4819-98BC-88E8173D3D16"));
Then you can create and object with Activator.CreateInstance and assign it to a dynamic to do late binding.
dynamic sage100 = Activator.CreateInstance(comType);
You will get no IntelliSense for this dynamic object. If you specify non-existing members (method or property names), you can still compile and run your C# code; however, a run-time exception will be thrown when you attempt to access these members.
Related
I am facing this error with C# (wpf).
This link has not been useful
Cannot be used across assembly boundaries because it has a generic type parameters that is an embedded interop type
Just to explain the structure of my program I can tell that:
I am using a library made by an external company. We can call it PCDLRN
In the solution I have a project made by me which incluse the types in the previous lib. In my library I define:
public ObservableCollection<PCDLRN.DimensionCmd> obcPcdlrnDimensionCommands = new ObservableCollection<PCDLRN.DimensionCmd>();
in order to by used in my main program.
So in short:
PCDLRN->MYLIB obcPcdlrnDimensionCommands --> MY PROGRAM myPcd.obcPcdlrnDimensionCommands
in my program I want to access the aforementioned ObservableCollection but it doesn't build giving the error in the title.
--EDIT---
As suggested I have changed from embedded = true to false by changing the prop as in picture but the error remains
As WasGoodDone remarked, you need to use the same class for both (all) assemblies you use for generics.
In other words, if you have assembly1, that references some interopAssembly, and assembly2, that references the same interopAssembly, and you switch embedded interop type to true, then you will have two copies of types from interopAssembly.
If you want to use some cross-references from assembly1 to assembly2, .NET can't resolve it, because from their point of view, the classes are different.
When you switch the embedded option off, your assembly will reference the other assembly which contains the interop types. And in this way you can use the interop types in different libraries.
So, if you have the problem described above, it means that you have at least two assemblies referencing PCDLRN, and you must switch off embedded interop type in all of them.
Embed Interop types was not shown on the property pages for my assembly (as in the question above), so I edited the project files directly to fix this problem:
I created a C# COM accessible dll that I want to consume in VB6
I was able to consume in VB6 my COM object with a hard reference to the TLB.
What I am trying to do now is to remove this reference and load it dynamically
I am creating it as follows:
Dim keylok As Object
Set keylok = CreateObject("MyClassLib.MyObject")
I get the Run-time error 424 "Object Required" once I hit the second line.
But when I create it as follows:
Dim keylok As MyObject
Set keylok = CreateObject("MyClassLib.MyObject")
It works fine.
I am not sure why would that make a difference. Anyway I cannot use the second one because I would still need to have the physical reference.
I tried also as a sort of debugging to write to file in my COM object constructor to if it really gets called. And yes it does, I'm even able to call other methods in my COM object sucessfully inside the constructor.
I was even able to load dynamically and consume it from another C# app using:
dynamic myObj = Activator.CreateInstance(Type.GetTypeFromProgID("MyClassLib.MyObject"));
Did any one encounter something like that before?
I found the solution with the help of #rskar input. So, I thought I'm gonna answer my question, in case any one faces the same problem.
My object didn't impelement IDsipatch. So all I had to do it to decorate my C# COM interface with InterfaceType(ComInterfaceType.InterfaceIsDual) So it implements both IUnknown and IDispatch.
Originally it was decorated with InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
I think you are going to require the .tlb anyway. COM objects need to be capable of being marshalled as the .Net hosting runs on a different thread to the VB6 runtime. The default marshalling uses information from the typelibrary to do this. IDIspatch has 4 methods and 2 of these are to do with accessing type information. So possibly if you removed the .tlb, when you create the IDispatch COM attempts to call up the ITypeInfo from this and dies failing to load the registered typelibrary. If you eliminate the .tlb you will become unable to be marshalled and likely you would have to provide a custom marshaller for your interface.
So I was looking to play some audio in C# and I found this:
which basically says to reference quartz.dll and use the FilgraphManagerClass.
This is perfect for my application since I would like to be able to start playing the song at specific points within the song. One can do this by setting FilgraphManagerClass.CurrentPosition. Also, I wanted the song to play in the background without any special player popping up, which happens when using this dll.
Unfortunately for me, when I try to do as the example suggests, Visual Studio 2010 Express complains and tells me "Interop type FilgraphManagerClass cannot be embedded." I am allowed to use the FilgraphManager interface, but that is missing the CurrentPosition property and any seeking ability.
This article suggests just finding the appropriate interface. But there doesn't appear to be one that really matches the FilgraphManagerClass. It also briefly talks about the safety involved in embedding assemblies
To use the class, I ended up right clicking on the QuartzTypeLib reference and changing the setting Embed Interop Types to false. Now everything works as it's supposed to.
Ok... finally my questions:
Is it safe to change the Embed Interop Types setting like I did for the QuartzTypeLib?
Is that true in general of all COM types?
What is this embedding and metadata stuff and why would it be safe or not?
Are there dlls that one CAN trust?
You need to ignore the safety argument, it is just nonsense. The issue is that the Embed Interop Type feature requires types to have a one-to-one match with the interface in the COM server. They must have a [Guid] attribute that matches. That attribute allows them to declare that types loaded from different assemblies are compatible, even though they came from different assemblies. The match on the Guid is the key.
Which is a problem with the classes whose name end in "Class". They are 'fake' classes, synthesized from the real COM coclasses. It solves a problem with .NET not supporting multiple inheritance. Since they are auto-generated, their [Guid] doesn't match a CLSID in the COM type library and the type cannot be embedded because their is no way to verify type equivalence.
You can very often avoid the multiple inheritance problem and just create an instance of the coclass without the "Class" postfix. Certainly in this case:
var player = new QuartzTypeLib.FilgraphManager();
player.RenderFile(#"c:\temp\test.avi");
Compiles and runs, doesn't play. But that's a different problem, you should use Windows Media Player instead. Add a reference from the COM tab.
Disabling EIT is not really an issue, you just get an interop.dll file in your build directory that you need to deploy on the user machine. EIT was really designed to solve a problem with PIAs (Primary Interop Assemblies), a problem that you don't have here since you are not exposing the native COM interfaces to any other assemblies.
Say I've got a load of COM types and I'd like to check if a particular type has been registered. I can use Activator.CreateInstance to actually try and create the class, but I was wondering if there's a simpler way actually check in advance if the class is actually registered.
I'd prefer not to go to the registry directly - I'm looking for something easy to use like the Activator.CreateInstance call above.
Thanks
NB. Activator.CreateInstance doesn't directly create COM class instance, it requires an interop assembly to have been generated and installed (e.g. by tlbimp.exe)—but this makes no difference here.
The simplest way to check without reading the registry is to try creating an instance and catch the possible exceptions due to the type not being available. (E.g. COMException if the underlying component is not installed correctly, TypeLoadException (IIRC) if the interop assembly is missing.)
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);
}
.....