![]() |
Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Hallo,
ich bastel momentan an einem COM-Addin für Outlook welches in C# entsteht. Lange Rede kurzer Sinn, ich komme nicht drum herum 3-4 mit der Extended Mapi zu machen. Das geht aber nur in C++ oder Delphi. Also wollte ich eine Delphi DLL schreiben die die gebrauchten Funktionen liefert. Damit das funktioniert muss der DLL die Session übergeben werden.
Delphi-Quellcode:
Damit bekomme ich einen Pointer auf ein IUnknown Object.
IntPtr ms = Marshal.GetIUnknownForObject(olNamespace.Session.MAPIOBJECT);
Was muss jetzt in dem function Kopf in der Delphi DLL stehen damit das übergeben wird. Desweiteren würde ich gerne wissen wie ich danach wieder auf das IUnknown Objekt in Delphi zugreifen kann. Ich weiss lediglich das wenn ich das IUnknown Projekt habe ich mit IUnknown.QueryInterface wieder an die gewollte IMapiSession komme, Im Voraus schonmal Danke Jonny |
Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Hallo,
das Interface IMAPISession muss in Delphi definiert sein. Wenn das der Fall ist einfach so:
Delphi-Quellcode:
Wenn du sicher bist, ein Interface eine bestimmte Schnittstelle unterstützt, dann kannst du den as Operator verwenden.
procedure DllProc(AMAPIObject: IUnknown); stdcall;
var AMAPISession: IMAPISession; begin AMAPISession := AMAPIObject as IMAPISession; end; Wenn du nicht sicher bist, ob ein Interface eine bestimmte Schnittstelle unterstützt, dann verwende QueryInterface. Ciao Chris |
Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Hallo,
ich habe das jetzt mal so eingebaut wie du geschrieben hast, leider bekomme ich schon beim Aufruf einen Fehler (SEHException). Gibt es eine Möglichkeit das zu debuggen in Delphi (An Prozess hängen hat nicht geklappt) Ich habe das versucht so zu implementieren: in C#
Delphi-Quellcode:
in Delphi:
[DllImport("eMapi.dll")]
public static extern void Profile(IntPtr ms);
Delphi-Quellcode:
Noch ne Idee was daran falsch ist?
procedure Profile(ms: IUnknown); stdcall;
Gruss Jonny |
Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Hallo,
was machst du den in der Delphi Funktion? Zeig mal den Code. Der Aufruf der Funktion selbst sollte problemlos funktionieren, hab ich grad selbst aus probiert.
Code:
[DllImport("TestDll.DLL")]
private static extern void TestProc(IntPtr Intf); private void button5_Click(object sender, EventArgs e) { IntPtr intf = Marshal.GetIUnknownForObject(this); TestProc(intf); }
Delphi-Quellcode:
Bei mir kommt dann die MessageBox. Also muss in der Funktion irgendwas schief laufen.
procedure TestProc(Intf: IUnknown); stdcall;
begin ShowMessage('TestProc: ' + IntToStr(Integer(Intf))); end; exports TestProc; Ciao chris |
Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Guten Morgen,
erstmal vielen Dank für deine Hilfe. Du hast vollkommen Recht, der Aufruf klappt auch, der Fehler liegt in der Delphi Funktion. Die sieht momentan so aus:
Delphi-Quellcode:
Problem ist das folgende Zeile NICHT die IMapiSession liefert.
procedure getProfile(Intf: IUnknown); stdcall;
const pbGlobalProfileSectionGuid : TMAPIUID = (ab:($13,$DB,$B0,$C8,$AA,$05,$10,$1A,$9B,$B0,$00,$AA,$00,$2F,$C4,$5A)); var lppprofsect : Iprofsect; propProfile : PSPropValue; value : String; hr : Hresult; session : IMapiSession; begin value:=''; Intf.QueryInterface(IID_IMAPISession, session); hr:=session.OpenProfileSection(PMAPIUID(@pbGlobalProfileSectionGuid),IID_IProfSect,MAPI_MODIFY, lppProfSect); if (hr = S_OK) then begin propprofile:=nil; if (S_OK = HrGetOneProp(lppprofsect, PR_PROFILE_NAME, propProfile)) then value:=propprofile.value.lpsza; if assigned(propprofile) then mapifreebuffer(propprofile); propprofile:=nil; end else if (hr<>S_OK) then begin end; lppProfSect:=nil; ShowMessage(value); end;
Delphi-Quellcode:
Deswegen knallt es dann bei "OpenProfileSection" weil session nil ist.
Intf.QueryInterface(IID_IMAPISession, session);
Hast du da noch eine Idee woran das liegen könnte? Ausserdem möchte ich eine andere Fragen nochmal wiederholen, ist es möglich die Delphi DLL zu debuggen? Es ist immer relativ umständlich zu Debugzwecken immer MessageBoxen einzubauen. Gruss Jonny |
Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Interfaces zwischen .Net und Delphi auszutauschen ist gar nicht so schwer wie man denkt...
Delphi Library:
Delphi-Quellcode:
C# App:
library CSharpInterop;
uses SysUtils; type ISampleInterface = interface ['{4B82AD42-D2B9-4ED7-82D9-87E8EA471923}'] function GetSomeValue : Integer; safecall; end; function TakesManagedInterface(const aInstance : IUnknown) : Integer; stdcall; export; var typedInstance : ISampleInterface; begin if Supports(aInstance, ISampleInterface, typedInstance) then result := typedInstance.GetSomeValue() else result := -1; end; exports TakesManagedInterface; end.
Code:
Wichtig sind eigentlich nur die Attribute über dem Interface.
[ComVisible(true)]
[Guid("4B82AD42-D2B9-4ED7-82D9-87E8EA471923"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface ISampleInterface { int GetSomeValue(); } class SampleClass : ISampleInterface { public int Value { get; set; } public int GetSomeValue() { return Value; } } class Program { [DllImport("CSharpInterop", EntryPoint = "TakesManagedInterface", CallingConvention = CallingConvention.StdCall)] static extern int CallDelphiFunction(IntPtr instance); static void Main(string[] args) { var instance = new SampleClass { Value = 123456 }; var value = CallDelphiFunction(Marshal.GetIUnknownForObject(instance)); } } Die GUID darf keine Curlies enthalten, und das Interface muss als IUnknown deklariert sein. Sonst springst du in die falschen Method slots. Außerdem muss es ComVisible sein, sonst wird dir die CLR keinen RuntimecallableWrapper drumrum bauen. Also das Ergebnis von "Marshal.GetIUnknownForObject", was du aus Delphi sehen würdest. |
Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Hallo,
du kannst unter Start->Parameter die .Net Anwendung als Hostanwendung anzugeben und dann das Delphi Dll Projekt starten. Dann scheint das IUnkown Interface die Schnittstelle IMAPISession nicht zu unterstützen. Bist du sicher, dass das MAPIOBJECT wirklich die IMAPISession unterstützt? Vielleicht kannst du auch das Session Objekt direkt als IDispatch Objekt zurück liefern (wenn das Session Objekt IDispatch unterstützt) und per Latebinding zugreifen.
Delphi-Quellcode:
Ciao Chris
procedure TestProc(Intf: IDispatch);
var ov: OleVariant; begin ov := Intf; ov.IrgendeinePropOderProc; end; |
Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Hallo,
das holen der IMapiSession wird unterstützt. Ich habe hier ein Beispiel in C++ von CodeProject was funktioniert:
Delphi-Quellcode:
Das IUnknown kommt auch nach meiner Erkenntnis richtig in Delphi an, zumindest das Handle stimmt in C# und Delphi
String^ Fabric::GetProfileName(Object^ mapiObject)
{ // the result returned to the calling method String^ result = nullptr; // pointer to IUnknown interface IUnknown* pUnknown = 0; // pointer to the MAPI session interface LPMAPISESSION lpMAPISession = 0; // pointer to a profilesection interface LPPROFSECT lpProfileSection = 0; // pointer to a structure that receives the result from HrGetOneProp LPSPropValue lpSPropValue = 0; // if we have no MAPIObject everything is senseless... if (mapiObject == nullptr) throw gcnew System::ArgumentNullException ("mapiObject","The MAPIObject must not be null!"); try { // retrive the IUnknon Interface from our MAPIObject comming from Outlook. pUnknown = (IUnknown*)Marshal::GetIUnknownForObject(mapiObject).ToPointer (); // try to retrieve the IMAPISession interface, if we don't get it, everything else is sensless. if ( pUnknown->QueryInterface (IID_IMAPISession, (void**)&lpMAPISession) != S_OK) throw gcnew Exception("QueryInterface failed on IUnknown for IID_IMAPISession"); // use the OpenProfileSection of the MAPISession object to retrieve a pointer to the current profilesection interface if( lpMAPISession->OpenProfileSection((LPMAPIUID)GLOBAL_PROFILE_SECTION_MAPIUID ,NULL,STGM_READ, &lpProfileSection) != S_OK) throw gcnew Exception("OpenProfileSection method failed!"); // use the HrGetOneProp method to retrieve the profile name property // the lpPropValue pointer points to the result value if (HrGetOneProp(lpProfileSection,PR_PROFILE_NAME_W,&lpSPropValue) != S_OK) throw gcnew Exception("HrGetOneProp failed for property PR_PROFILE_NAME_W !"); // create a managed string from the unmanaged string. return gcnew String( lpSPropValue->Value.lpszW ); } catch (Exception^ ex) { // if an error occures get the MAPI error code DWORD dw = GetLastError(); // and translate it into a human readable message if (dw != 0) throw gcnew Exception(GetErrorText(dw),ex); throw ex; } finally { // Free buffer allocated by MAPI if (lpSPropValue != 0) MAPIFreeBuffer(lpSPropValue); // cleanup all references to MAPI Objects if (lpProfileSection!=0) lpProfileSection->Release(); if (lpMAPISession!=0) lpMAPISession->Release(); if (pUnknown!=0) pUnknown->Release(); } } überein. Das QueryInterface liefert den Mapi Fehler: MAPI_E_CALL_FAILED In C++ klappt es komischerweise :( Gruss Jonny |
Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Moin,
ich möchte mich erst nochmal für eure Hilfe bedanken. Desweiteren habe ich die Lösung für das Problem gefunden. Man musste vorher noch ein MapiInitialize aufrufen da sich der Aufruf "ausserhalb" befindet. Nun klappt alles :) Gruss Jonny |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:04 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz