using System;
using System.Runtime.InteropServices;
namespace ComTestCSharp
{
[Guid("F1E80D2D-72F7-434F-86AB-DFC7BF10C447"), ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IComTest
{
[DispId(1)]
int AddFunction(int value1, int value2);
}
[Guid("0C216A19-E1B7-4b05-86D3-4C516BDDC041")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("ComTest")]
public class ComTest : IComTest
{
[DispId(1)]
public int AddFunction(int value1, int value2)
{
return value1 + value2;
}
}
}
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(AddFunction(5, 2));
}
[DllImport("ComTestCSharp.dll")]
private static extern int AddFunction(int value1, int value2);
}
}
|
|
|
|
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ComTestCSharp
{
[Guid("F1E80D2D-72F7-434F-86AB-DFC7BF10C447")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface IComTest
{
[DispId(1)]
int AddFunction(int value1, int value2);
[DispId(2)]
string GetMyProperty();
[DispId(3)]
string MyProperty { get; set; }
}
[Serializable]
[Guid("0C216A19-E1B7-4b05-86D3-4C516BDDC041")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
[ProgId("ComTest")]
public class ComTest : IComTest
{
public string MyProperty { get; set; }
public ComTest() { }
public int AddFunction(int value1, int value2)
{
return value1 + value2;
}
public string GetMyProperty()
{
MessageBox.Show("MyProperty: "+MyProperty);
return MyProperty;
}
}
}
Function MyTest()
Dim test As Long
Dim theObj As New ComTest
test = theObj.AddFunction(5, 6)
theObj.MyProperty = "Test"
Dim strValue As String
strValue = theObj.GetMyProperty()
Exit Function
End Function
Public Type MyType
A As String
B As String
C As String
End Type
|
|
namespace VisualPkAddIn
{
[Guid("744B3544-FDA6-4AE9-9CAD-15D10412DFE8")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class PkFunctions
{
public double Runden0(double zahl)
{
return MathExtensions.Round0(zahl);
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", Environment.SystemDirectory + @"\mscoree.dll", RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(@"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(@"}\");
s.Append(subKeyName);
return s.ToString();
}
}
}
|
|
<ComClass(myClass.ClassId, myClass.InterfaceId, myClass.EventsId)> _
Public Class myClass
#Region "COM-GUIDs"
' Diese GUIDs stellen die COM-Identität für diese Klasse
' und ihre COM-Schnittstellen bereit. Wenn Sie sie ändern, können vorhandene
' Clients nicht mehr auf die Klasse zugreifen.
Public Const ClassId As String = "c978ce23-7cee-43e2-a676-355f586b2ded"
Public Const InterfaceId As String = "342c5708-5da9-4773-81d3-bc7fb17ae263"
Public Const EventsId As String = "1a8b4b0a-7f7d-4f9f-add3-82d9830248f5"
#End Region
%systemroot%\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe "Pfad zu meiner DLL.dll" /unregister
%systemroot%\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe "Pfad zu meiner DLL.dll" /tlb:meineDLL.tlb /codebase
|
|
[ComVisible(true)]
[Guid("e272a619-3b80-42a3-9156-df57ed9eb3f7")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IFach
[Serializable]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[Guid("5330F296-FC59-45C3-8368-7F1A022FA635")]
public class Fach : IFach
|
|
|
Ich habe meine zu veröffentlichende DLL genauso aufgebaut, wie Du es beschreibst.
Trotzdem bekomme ich keinen Zugriff auf die Funktion. Kann ich Dir vielleicht mal meine Test-DLL zusenden, damit Du bei Dir testen kannst, ob Du Zugriff auf die Funktion bekommst. Wenn ja, dann muss ich ja einen Fehler beim Registrieren der DLL im System, oder in der Zielanwendung machen. Bekommst Du keinen Zugriff, muss der Fehler in der DLL selbst liegen. – Carsten Ilwig 17.06.2011
|
||
|
Ich hätte ja alles um es zu testen. Dein Code oben scheint vollständig zu sein. Werde mir es anschauen. Zur Zeit bin ich aber im Büro, Job, und kann nicht einfach so machen. :-)
– GENiALi 17.06.2011
|
||
|
Konnte es jetzt nich sein lassen und habs getestet. Das Zeugs wird in der Registiry richtig abgelegt. Dort finde ich keinen Unterschied. Mit einem VBS scirpt gibt auch einen Fehler.
Test.vbs -------- set obj = CreateObject("ComTestCSharp.ComTest") MsgBox obj.AddFunction(2, 5) Vermutung ist noch da, dass es an irgend welchen Berechtigungen liegen könnte. Aber wo, das weiss ich noch nicht. :-/ – GENiALi 17.06.2011
|
Nachtrag: Anstelle DLL-Import, eine COM-Referenz ins Projekt aufnehmen (da die DLL ja COM registriert ist, sollte sie bei Add References in der COM Lasche aufscheinen) und dann die Objekte verwenden, wie man es von COM Objekten kennt.
Und P/Invoke == Platform Invoke bezieht sich auf Native DLLs (C++), deren Funktionen man aufrufen möchte. Die haben nichts mit COM, oder managed Code der COM visible ist, zu tun.
|
|
|
|
|
|
|
|
|
Hast du auch die regasm aus dem "Windows\Microsoft.NET\Framework64\v2.0.50727" verwendet? 64Bit!! Mit den Optionen "/register /codebase /tlb" ?
– Floyd 17.06.2011
|
||
|
Warum soll ich die regasm von .NET V2 verwenden?
Wenn ich diese nehme, kommt die Meldung, dass die DLL angeblich keine .NET-Assembly ist. Ich verwende deshalb regasm aus dem Ordner "C:\Windows\Microsoft.NET\Framework64\v4.0.30319" also von .NET V4. – Carsten Ilwig 17.06.2011
|
||
|
Sorry, das mit .Net 4 hab ich überlesen. Mir war eher wichtig auf die 64-Bit-Version hinzuweisen. Viele machen den Fehler und benutzen nur die 32-Bit Version und wundern sich dann warum es im 64-Bit-Modus nicht funktioniert.
– Floyd 17.06.2011
|
||
|
@carsten: nein, das meinte ich nicht. sondern dieses:
http://www.developmentnow.com/g/21_2004_1_0_0_105068/ComInterfaceType-InterfaceIsDual.htm – nabuchodonossor 20.06.2011
|
||
|
aber ganz abgesehen davon: ich arbeite auf einer 64 bit kiste mehr oder weniger problemlos mit vb6 UND com interopt. natürlich habe ich als target x86, und daher in vb6 keine probleme mit com dlls die unter .net erstellt wurden.
– nabuchodonossor 20.06.2011
|
|
|
[Assembly: ComVisible(True)]
//The following GUID is for the ID of the typelib if this project is exposed to COM
[Assembly: Guid("86798dbb-1cc6-4799-8c05-3994daa3db81")]
|
|
|
|
|
Wäre aber unlogisch. Wenn die C#-DLL die richtigen COM-Schnittstellen exportiert und der C#-Client mit C# umgehen kann (wobei wir wissen das letzteres definitiv zutrifft) ist es egal in welcher Sprache die COM-DLL geschrieben ist.
– Floyd 17.06.2011
|
||
|
Wenn ich die C#-Dll aus einer anderen C#-Anwendung über COM heraus aufrufe, weiß die aufrufende Anwendung doch gar nicht, dass es sich bei dem COM-Object ja eigentlich um eine C#(.NET)-DLL handelt, da der Zugriff ja reinweg über die Typbeschreibung erfolgt.
Außerdem bekomme ich genau den gleichen Fehler "Einsprunkpunkt nicht gefunden.." wenn ich versuche in VB6 die C#-DLL zu verwenden. Aber trotzdem Danke für Deinen Hinweis. – Carsten Ilwig 17.06.2011
|
||
|
Ja, erscheint mir auch nicht unbedingt logisch. Aber ich erinnere mich genau an diesen Hinweis damals. Wollte das nur mal einwerfen.
– KN 17.06.2011
|
||
|
Ich habe das noch einmal mit meinem Kollegen diskutiert, der in Com ebenfalls sehr erfahren ist. Er sagt auch, dass die P/Invoke-Funktionalität in diesem Fall gar nicht greift. Die AddFunction ist ja ein nicht-statisches Member der Klasse. Du müsstest also erst einmal die Klasse instantiieren, bevor du auf eine Methode darin zugereifen kannst. Uns ist keine P/Invoke-Funktionalität bekannt, die sowas abbildet. Warum willst du denn zwischen 2 C#-Dlls unbedingt über Com zugreifen? Das geht doch auch direkt.
– KN 17.06.2011
|
||
|
Mir ist noch etwas eingefallen: Du willst entweder eine C#-Dll unter Com veröffentlichen, um sie dann unter einer anderen Umgebung aufzurufen, oder du willst den umgekehrten Weg gehen. Sehe ich das richtig? Wenn das so ist: welche Richtung willst du gehen, und welches ist die andere Umgebung? Wir haben hier schon vieles in allen möglichen Richtungen gemacht. Vielleicht kann ich dir ja für das, was du letztendlich willst, einen Tipp geben.
– KN 17.06.2011
|
||
|
Richtig, diese Konstellation, dass ich eine .NET-DLL in einer anderen .NET-Anwendung via COM aufrufe dient nur dem grundsätzlichem Funktionstest. Das eigentliche Ziel ist, auf die Funktionen aus der .NET-DLL von VB6 aus zuzugreifen.
Da aber die VB6-IDE nicht auf einem 64bit-System läuft (meinem Arbeitssystem) habe ich mir diesen Testfall konstruiert um nicht ständig zwischen den Systemen wechseln zu müssen. Wenn ich aus der .NET-Testanwendung heraus via COM auf meine Funktion in der .NET-DLL zugreifen kann, dann klappt es hoffentlich auch von VB6 aus. – Carsten Ilwig 17.06.2011
|
||
|
Mit VB6 haben wir noch nix gemacht, da kann ich nicht weiter helfen. Ich denke, dass P/Invoke hier das falsche Instrument ist. Schon alleine wegen der nicht-statischen Methode. Wenn wir .Net-Dlls mit Klassen und nicht-statischen Methoden aus anderen Umgebungen heraus aufrufen, instantiieren wir auch immer zuerst ein Objekt der Klasse, bei dem wir dann die Methode aufrufen. Ich habe deinen Code hier bei mir ausprobiert und bekomme den gleichen Fehler. Ich habe nichts gefunden, wie ich die Methode außen sichtbar machen kann (Anschauen mit Depends, einem Tools, das bis 2008 beim VS dabei war).
– KN 17.06.2011
|
Leider kann ich den so nicht bei meiner Anforderung verwenden, da das "ComRegisterFunctionAttribute" nur für statische Methoden ohne Rückgabetyp funktioniert und mann auch nur Parameter vom Typ 'Type' übergeben kann.