IronPython get to internal class from C# dll - c#

I'm using IronPython for fetching inner classes from C# dll.
for example:
namespace Platform.CardHost {
internal class ExtensionManager : IExtensionManager, IDisposable {
//... other code
IronPython Code
import clr
clr.AddReference('Platform.CardHost')
import Platform.CardHost.ExtensionManager
# raise ImportError: No module named ExtensionManager
# if it add to ref
clr.AddReference('Platform.CardHost.ExtensionManager')
# raise Error
# IOError: System.IO.IOException: Could not add reference to assembly
# Platform.CardHost.ExtensionManager
How can I import ExtensionManager? Or is this not possible?

So like I already wrote:
make ExtensionManager public if you want to access it from somewhere else than your assembly.
The definition of internalis
The type or member can be accessed by any code in the same assembly, but not from another assembly.
what you could do, to make it only available for another assembly is, to make it visible for a friend assembly:
using System.Runtime.CompilerServices;
using System;
[assembly:InternalsVisibleTo("my_friend_assembly")]
internal class ExtensionManager : IExtensionManager, IDisposable
{
}
else, I don't see any reason why making it internal but trying to access it from another assembly/your ironpython-script. Yeah, for friend assemblies, there are reasons, for sure.
for your new update: "I can't change class":
so maybe, the guy who wrote that class doesn't want you to import the class from elsewhere? That's the use of internal,protected,private and public.
Imho, it would be really bad to define in C# a class as internal, so you can't import it from C#, but IronPython still lets you import it.
for sure, you could try getting the code from the assembly, change it and make it again to a new assembly, like you wrote. But that's a lot of work and possibly in the end, it won't work.

Thanks to Matthias Burger for a fact that prompted the idea.
i try to decompile dll. because the file were large after he disassemble, it can't assemble without problem.
I wrote to the guy, he say me use C# interface ICardHost.
here how i use it, maybe for someone who meet similar problem.
clr.AddReference('Platform.CardHost')
from Platform import CardHost
from Platform.CardHost import ICardHost
host = CardHost.CardHost.CreateInstance(session)
# ExtensionManager is internal class but it available by interface
# here how to use C# interface
em = ICardHost.ExtensionManager.__get__(host)
as it in C#
// cardHost
public sealed class CardHost : Component, ICardHost
// ICardHost
public interface ICardHost {
IExtensionManager ExtensionManager { get; }

Related

C# creating a wrapper namespace?

In C#, how can I import all classes from one namespace into another namespace such that these classes are directly accessible from the second namespace?
I'm essentially attempting to rename a namespace in an externally visible manner.
Since code is worth a thousand words, given a DLL with the following namespace:
// Externally written DLL I have no control over.
namespace A
{
class ClassA {...}
}
I'd like to be able to create another DLL along the lines of:
// My DLL
namespace Wrapper
{
using A;
}
So that I can use it like:
// Final C# program.
using Wrapper;
var a = ClassA();
In python, I could accomplish what I want with import *:
# external.py
class ClassA:
...
# mymodule.py
from external import *
# final_program.py
import mymodule
a = mymodule.ClassA()
Disclaimer
I know this is a terrible idea, but I'm unfortunately being constrained by external requirements. The short version is that I have an external DLL that needs to interface with a proprietary system (EnScript, if you're curious). This proprietary system has restrictions on the naming of namespaces that the external DLL of course violates. Thus, I'm attempting to use the wrapper DLL to expose a namespace that is considered valid.
Related Questions
Talks about using in C# vs wildcard imports in java/python. Does not address issue of accessing from second namespace:
Import all subclasses like Java but in C#
C# equivalent to wildcard imports in Java
Namespaces in C# vs imports in Java and Python
Question about including classes in namespace. Issue was use of separate projects and so not applicable to this question:
How To Include Classes From Another Namespace In Assembly Instead of Writing Them Into A Separate DLL File?
You can't move a type to a different namespace (other than physically moving the code). The .NET type system uses the full namespace to uniquely identify the type.
But you can create an alias to mask the original namespace.
Let's say you have a class MyProject.Foo.Bar.Xyzzy.MyClass, and you are tired of typing MyProject.Foo.bar.Xyzzy. You can add a Using directive at the top of the code file like this:
Using DifferentNamespace = MyProject.Foo.Bar.Xyzzy;
Once you have done this, you can refer to the class with just
var c = new DifferentNamespace.MyClass();
You can even use this to include a different namespace in the current default namespace. This will compile:
namespace Example.Classes
{
class MyClass
{
}
}
namespace Example
{
using Example = Example.Classes;
class Test
{
static void Test1()
{
var c = new Example.MyClass(); //Not Example.Classes.MyClass
}
}
}
But unfortunately you have to leave the alias there; i.e., this won't compile:
namespace Example.Classes
{
class MyClass
{
}
}
namespace Example
{
using Example = Example.Classes;
class Test
{
static void Test1()
{
var c = new MyClass(); //Error
}
}
}

Create and Register a COM Server Object .NET

I've been following a set of tutorials (like this one) to create a simple COM server object.
Say I've got a simple hello world:
[ComVisible(true)]
[Guid("392930B3-9CD0-4247-8C69-83168D1C8F77")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("nathanr.HellowWorldCom")]
class HelloWorldCom : IHelloWorldCom
{
public int HelloWorld()
{
Console.WriteLine("Hello World!");
return 1;
}
}
With just as simple an interface:
[ComVisible(true)]
[Guid("C08205BE-1393-4070-AE57-FA47F0D653C3")]
interface IHelloWorldCom
{
[DispId(1)]
int HelloWorld();
}
And of course, can't forget the AssemblyInfo.cs file:
...
[assembly: ComVisible(true)]
[assembly: AssemblyKeyFile("HelloWorldCOM.snk")]
...
The problem is when I build the HelloWorldCom.dll and try to register it, regasm just sticks its tongue out at me:
RegAsm : warning RA00000 : No types were registered.
And just to cover my bases I cracked open Regedit and did a search for the ProgID. It wasn't there, which honestly wasn't a surprise.
Am I missing something obvious?
This whole test project is part of a larger (actually useful) set up which is also failing to register.
This will be a very long answer: add public
public class HelloWorldCom : IHelloWorldCom
There might be couple of issues:
You are selecting an incorrect .net framework. In my case, I was trying to register the dll with 2.0 framework, as opposed to 64 bit 4.0 framework
Your DLL is not publicly exposed.
Hope that resolves your issue.
Cheers

How to invoke C#/.NET namespace in IronPython?

I'm looking to replicate the following in IronPython and searching has so far been fruitless and/or disappointing.
namespace Groceries
{
public class ChocolateMilk : Milk
{
// Other stuff here
}
}
The idea would be that the compiled Python DLL will be loaded into a C# program through System.Reflection.Assembly.Load and a GetType("Groceries.ChocolateMilk") on the loaded DLL would not return null.
The most recent answer I was able to find was in 2008 and said that it was impossible without using the Hosting API - http://lists.ironpython.com/pipermail/users-ironpython.com/2008-October/008684.html.
Any suggestions on how to accomplish this would be greatly appreciated. Any conclusions that this is currently impossible to do via IronPython will also be appreciated, but less so.
I'm a bit confused on what you're asking here. Are you trying to instantiate that C# code in your IronPython modules? Or do you have the equivalent classes written in IronPython and you want to instantiate them in your C# code?
Based on the link you posted, I suppose you're going for the latter and have IronPython classes that you want instantiated in your C# code. The answer is, you cannot directly instantiate them. When you compile IronPython code to an assembly, you cannot use the types defined there with your regular .NET code since there is not a one-to-one mapping between IronPython classes and .NET classes. You would have to host the assembly in your C# project and instantiate it that way.
Consider this module, Groceries.py compiled to Groceries.dll residing in the working directory:
class Milk(object):
def __repr__(self):
return 'Milk()'
class ChocolateMilk(Milk):
def __repr__(self):
return 'ChocolateMilk()'
To host the module in your C# code:
using System;
using IronPython.Hosting;
using System.IO;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var engine = Python.CreateEngine();
var groceriesPath = Path.GetFullPath(#"Groceries.dll");
var groceriesAsm = Assembly.LoadFile(groceriesPath);
engine.Runtime.LoadAssembly(groceriesAsm);
dynamic groceries = engine.ImportModule("Groceries");
dynamic milk = groceries.ChocolateMilk();
Console.WriteLine(milk.__repr__()); // "ChocolateMilk()"
}
}
Otherwise to go the other way and create an instance of your .NET type in your IronPython code (as your title suggests). You'd need to add the path to your assembly, reference it, then you could instantiate it as needed.
# add to path
import sys
sys.path.append(r'C:\path\to\assembly\dir')
# reference the assembly
import clr
clr.AddReferenceToFile(r'Groceries.dll')
from Groceries import *
chocolate = ChocolateMilk()
print(chocolate)

Calling C# dll in vbscript

I am trying to call a C# dll from QTP (uses vbscript). I have tried a number of things with no success:
Visual Studio 2010
Create C# class libary (st.dll)
code:
using System;
using System.Collections.Generic;
using System.Text;
namespace st
{
public class Class1
{
public static int GetValue()
{
return 34;
}
}
}
regasm /codebase st.dll
fails 'because it is not a valid .NET assembly'
In QTP/vbscript, I have tried
extern.Declare micInteger, "GetValue", "e:\st.dll", "GetValue"
Returns message: 'Invalid procedure call or argument'
Regardless of QTP, I would greatly appreciate any insight on how to call the c# dll from a .vbs file.
I was able to get this working by doing the following:
Create a new C# dll in VS 2010.
namespace st4
{
public class st4_functions
{
public int GetValue()
{
return 34;
}
}
}
In QTP I added the following lines:
Set obj = DotNetFactory.CreateInstance("st4.st4_functions", "c:\\st4.dll")
MsgBox obj.GetValue()
Thanks to all that responded to my problem. Though I did not do the COM solution, it got me thinking that I could stay with .NET and led to this solution. Good job all!
EDIT:
I created a blog post to detail the steps and provide additional information:
http://www.solutionmaniacs.com/blog/2012/5/29/qtp-calling-c-dll-in-vbscript.html
As Marc said, but I think it merits an answer. If you ensure that your dll will be available though the COM mechanics, your script should be able to call into it with things like CreateObject.
How to register .NET assembly for COM interop
Your function is static. Static class members can't be matched up to interface members, and if it can't implement a .NET interface then it certainly won't implement a COM interface.

warning MSB3391: <DLL> does not contain any types that can be unregistered for COM Interop

I've made a simple C# DLL (that's part of a much larger project) using VS2005. I need to use the DLL in Excel via VBA code so I am using COM Interop on the assembly. I am trying to make the build process automatically generate the necessary TLB file so that I don't need to go to the command line and use regasm after every build.
My problem is that although the DLL compiles and builds fine, it does not generate a TLB file. Instead, the error in the title prints out in the output box.
I've gotten other DLLs to build TLB files by going to the project's properties in VS2005 -> Build -> Output -> Check "Register for COM interop". Also I have [assembly: ComVisible(true)] in the AssemblyInfo.cs.
Here's the summary of the source for the problem DLL and the DLL that it references for a return type:
using System;
using System.IO;
using System.Runtime.InteropServices;
using SymbolTable;
namespace ProblemLibrary
{
public class Foo
{
public Foo(string filename)
{
...
}
// method to read a text file into a SymbolTable
public SymbolTable BuildDataSet(string[] selected)
{
...
}
}
}
Here is a summary of SymbolTable.dll. It holds a return type that ProblemLibrary uses.
using System;
using System.Collections.Generic;
namespace SymbolTable
{
public class SymbolTable
{
readonly Dictionary<SymbolInfoStub, string> _symbols = new Dictionary<SymbolInfoStub, string>();
/*methods that interact with Dictionary snipped*/
}
}
You need to have ctor without any params.
You should have GuidAttribute and ProgIdAttribute around the classes.
Its better to mark the assembly as ComVisible(false) and mark explicitly the classes that need export.
Use interfaces for your classes.
Make sure the you have GuidAttribute in the assembly level.
[Guid("<PUT-GUID-HERE-1>")]
[ComVisible(true)]
interface IFoo
{
void DoFoo();
}
[Guid("<PUT-GUID-HERE-2>")]
[ComVisible(true)]
[ProgId("ProgId.Foo")]
class Foo : IFoo
{
public void DoFoo()
{
}
}
In the AssemblyInfo.cs file, make sure you have the following:
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]
UPDATE:
Read: How can I make use of .NET objects from within Excel VBA?
Which links to:
http://richnewman.wordpress.com/2007/04/15/a-beginner%E2%80%99s-guide-to-calling-a-net-library-from-excel/
I saw a similar problem. I got an error like:
warning MSB3391: does not contain any
types that can be unregistered for COM
Interop.
I followed all the rules (ComVisible, etc.) but nothing worked.
Solution: I had to put something in the default constructor so that it would not be optimized away. The moment I had something there, the registration finished with no message and the component was visible in the registry.
Interesting note: a friend of mine managed to register the original DLL with the empty default constructor on his machine (64-bit Windows-7, VS2008-Professional, like mine). However, his REGASM.EXE was:
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\regasm.exe
while mine was:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe
So it could be some difference between versions of the .NET framework - maybe the later version is optimizing too much and the REGASM does not account for that.

Categories

Resources