2016-04-22 19 views
0

Ich versuche C# -Code aus C++ aufzurufen. Also habe ich den COM-Interop-Weg gewählt. Jetzt habe ich C# -Code:C# von C++ aufrufen, Rückgabewert

namespace ToBeCalled 
{ 
    [Guid("9329feaf-b293-4093-a7d8-6128f52b30a6")] 
    [ComVisible(true)] 
    public interface IInterface 
    { 
     int Write(string toWrite); 
    } 
} 

namespace ToBeCalled 
{ 
    [Guid("e4105e40-2d6b-4b7c-ae42-d2f9c405a2a0")] 
    [ComVisible(true)] 
    public class ClassYouWantToUse : IInterface 
    { 
     public int Write(string toWrite) 
     { 
      System.Console.WriteLine(toWrite); 
      return 1; 
     } 
    } 
} 

und C++ Code

#import "...\\ToBeCalled.tlb" 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    // Initialize COM. 
    HRESULT hr = CoInitialize(NULL); 

    // Create the interface pointer. 
    ToBeCalled::IInterfacePtr piTest(__uuidof(ToBeCalled::ClassYouWantToUse)); 

    long lResult = 0; 

    // Call the Add method. 
    piTest->Write("hi", &lResult); 

    wprintf(L"The result is %d\n", lResult); 

    // Uninitialize COM. 
    CoUninitialize(); 
    return 0; 
} 

Wenn ich diese Kompilierung versuchen, natürlich heißt es, dass Schreiben nicht zwei Argumente nimmt. Ich habe die MSDN gesehen, wo sie ein Beispiel haben, und sie nehmen den Rückgabewert auf diese Weise. Meine Frage ist also, wie kann ich den Rückgabewert der Funktion erhalten? Wenn ich den Anruf auf

aktualisiert, dann schlägt die Ausführung fehl bei Unhandled Exception. Wenn ich dieses Beispiel versuchte, ohne Wert zurückzugeben, so ist die Deklaration des Rückgabewerts für Methode ungültig, als alles in Ordnung funktioniert.

+0

Ich fand, dass es notwendig ist, Parameter zu C# hinzuzufügen, und dann kann ich das zweite Argument verwenden, das den Ergebniswert haben wird. Ok, also für Int ist das Problem gelöst, aber wie kann ich die Zeichenfolge so senden? –

+0

Normalerweise sollte es möglich sein, einen Wert zurückzugeben, und nicht über den Parameter "[out]". Was ist genau die Ausnahme? Haben Sie den verwalteten Anruf bereinigt? –

Antwort

2

Ihr Servercode ist OK und Sie müssen keinen out Parameter verwenden.

sollte der Client-Code einfach wie folgt aussehen:

long result = piTest->Write("hi"); 

Wenn Sie in .tlh Datei generiert schauen, sehen Sie, dass die Unterschrift sehen ist so etwas wie:

long Write(_bstr_t toWrite); 

Dies wird eine generierte Wrapper-Code und Sie verwechseln es wahrscheinlich mit dem Raw-COM-Aufruf, der ebenfalls Teil der Datei tlh ist und wie folgt aussieht:

virtual HRESULT __stdcall raw_Write(BSTR toWrite, long* pRetVal) = 0; 

Der Wrapper ist praktischer: Er ruft den Raw-COM-Aufruf intern auf und verarbeitet den Rückgabewert - daher wird der Rückgabewert normalerweise von der Funktion zurückgegeben (statt als [out, retval] Argument) und wenn das Ergebnis von Raw-Aufruf bezeichnet einen Fehler (eine fehlgeschlagene HRESULT) eine _com_error Ausnahme wird ausgelöst.

Für Details können Sie sich eine andere generierte Datei mit der Erweiterung tli ansehen, die die Implementierung der Wrapper-Methode enthält.

+0

danke, ich versuche es. Ja, ich war mit HRESULT verwirrt. Ist hier eine Freigabe nötig, wenn ich String von C# zurückgebe? Wenn ja, wie? –

+1

Sie geben keine Zeichenfolge zurück, sodass die Zuordnung nicht aufgehoben wird. Wenn Sie eine neue Methode erstellen, die eine Zeichenkette zurückgibt (definiert als '[out, retval]' Argument in 'idl' Definition), entspricht sie den Standard-COM Regeln und im Allgemeinen müssen Sie sie über' SysFreeString' API (zB wenn Sie einen rohen Anruf verwenden). "# Import" generiert jedoch auch einen "intelligenten" Wrapper, der ein "bstr_t" zurückgibt, das dafür sorgt, dass die Zuordnung für Sie aufgehoben wird. Wenn Sie diese Methode verwenden, gibt es also keine Zuordnung zum Deallocate. –