AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Parameterprobleme beim Aufruf einer Delphi DLL aus C#
Thema durchsuchen
Ansicht
Themen-Optionen

Parameterprobleme beim Aufruf einer Delphi DLL aus C#

Ein Thema von JonnyGuitar · begonnen am 26. Okt 2009 · letzter Beitrag vom 28. Okt 2009
Antwort Antwort
JonnyGuitar

Registriert seit: 4. Jun 2004
233 Beiträge
 
#1

Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 26. Okt 2009, 16:11
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.

IntPtr ms = Marshal.GetIUnknownForObject(olNamespace.Session.MAPIOBJECT); Damit bekomme ich einen Pointer auf ein IUnknown Object.

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
the only thing to fear is runnin' out of beer
  Mit Zitat antworten Zitat
Chris.R

Registriert seit: 8. Sep 2009
Ort: Nürnberg
68 Beiträge
 
Delphi 2010 Professional
 
#2

Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 26. Okt 2009, 16:19
Hallo,

das Interface IMAPISession muss in Delphi definiert sein. Wenn das der Fall ist einfach so:

Delphi-Quellcode:
procedure DllProc(AMAPIObject: IUnknown); stdcall;
var
  AMAPISession: IMAPISession;
begin
  AMAPISession := AMAPIObject as IMAPISession;

end;
Wenn du sicher bist, ein Interface eine bestimmte Schnittstelle unterstützt, dann kannst du den as Operator verwenden.
Wenn du nicht sicher bist, ob ein Interface eine bestimmte Schnittstelle unterstützt, dann verwende QueryInterface.

Ciao Chris
Guten Morgen! … Und falls wir uns heute nicht mehr sehen, Guten Tag, Guten Abend und Gute Nacht!
  Mit Zitat antworten Zitat
JonnyGuitar

Registriert seit: 4. Jun 2004
233 Beiträge
 
#3

Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 26. Okt 2009, 17:08
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:
[DllImport("eMapi.dll")]
public static extern void Profile(IntPtr ms);
in Delphi:
procedure Profile(ms: IUnknown); stdcall; Noch ne Idee was daran falsch ist?


Gruss Jonny
the only thing to fear is runnin' out of beer
  Mit Zitat antworten Zitat
Chris.R

Registriert seit: 8. Sep 2009
Ort: Nürnberg
68 Beiträge
 
Delphi 2010 Professional
 
#4

Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 27. Okt 2009, 08:53
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:
procedure TestProc(Intf: IUnknown); stdcall;
begin
  ShowMessage('TestProc: ' + IntToStr(Integer(Intf)));

end;


exports
  TestProc;
Bei mir kommt dann die MessageBox. Also muss in der Funktion irgendwas schief laufen.

Ciao chris
Guten Morgen! … Und falls wir uns heute nicht mehr sehen, Guten Tag, Guten Abend und Gute Nacht!
  Mit Zitat antworten Zitat
JonnyGuitar

Registriert seit: 4. Jun 2004
233 Beiträge
 
#5

Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 27. Okt 2009, 10:08
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:
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;
Problem ist das folgende Zeile NICHT die IMapiSession liefert.
Intf.QueryInterface(IID_IMAPISession, session); Deswegen knallt es dann bei "OpenProfileSection" weil session nil ist.

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
the only thing to fear is runnin' out of beer
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#6

Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 27. Okt 2009, 10:27
Interfaces zwischen .Net und Delphi auszutauschen ist gar nicht so schwer wie man denkt...
Delphi Library:
Delphi-Quellcode:
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.
C# App:
Code:
[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));
   }
}
Wichtig sind eigentlich nur die Attribute über dem Interface.
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.
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat
Chris.R

Registriert seit: 8. Sep 2009
Ort: Nürnberg
68 Beiträge
 
Delphi 2010 Professional
 
#7

Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 27. Okt 2009, 10:41
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:
procedure TestProc(Intf: IDispatch);
var
  ov: OleVariant;
begin
  ov := Intf;

  ov.IrgendeinePropOderProc;
end;
Ciao Chris
Guten Morgen! … Und falls wir uns heute nicht mehr sehen, Guten Tag, Guten Abend und Gute Nacht!
  Mit Zitat antworten Zitat
JonnyGuitar

Registriert seit: 4. Jun 2004
233 Beiträge
 
#8

Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 27. Okt 2009, 12:18
Hallo,

das holen der IMapiSession wird unterstützt.
Ich habe hier ein Beispiel in C++ von CodeProject was funktioniert:

Delphi-Quellcode:
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();
      }

   }
Das IUnknown kommt auch nach meiner Erkenntnis richtig in Delphi an, zumindest das Handle stimmt in C# und Delphi
überein. Das QueryInterface liefert den Mapi Fehler: MAPI_E_CALL_FAILED
In C++ klappt es komischerweise


Gruss Jonny
the only thing to fear is runnin' out of beer
  Mit Zitat antworten Zitat
JonnyGuitar

Registriert seit: 4. Jun 2004
233 Beiträge
 
#9

Re: Parameterprobleme beim Aufruf einer Delphi DLL aus C#

  Alt 28. Okt 2009, 11:10
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
the only thing to fear is runnin' out of beer
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:01 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz