Wie C# Dll in C++ Builder (VCL-Anwendung) über COM nutzen?



  • Hallo,

    ich habe mehrere Anleitungen gefunden wie man eine C# dll COM-Kompatibel macht.

    Nun wollte ich versuchen ob ich nicht eine aktuelle C# dll (.Net 4.6) im C++ Builder nutzen kann (wenn ja, wäre es ein Weg um unsere C++ Builder Anwendung nach und nach zu Migrieren), doch hatte ich mit keiner Beschreibung bislang Erfolg. Ich habe die .Net Bibliothek zwar erfolgreich mittels RegAsm registieren können, unter dem C++ Builder habe ich diese aber nicht in dem Fenster "Import Component/Import a Type Library" gefunden.

    Hat jemand damit Erfahrungen und kann eine simple Schritt für Schritt Anleitung geben, was einmal auf C# und auf C++ Builder-Seite nötig ist?



  • Du benötigst wohl eine Type-Library Datei (.tlb), s.a. Calling Managed .NET C# COM Objects from Unmanaged C++ Code (s. "Registration of the COM Class and Interfaces"):

    REGASM MyInterop.dll /tlb:com.MyInterop.tlb
    

    (ob die Schritte vorher auch dringend notwendig sind, also die C#-DLL im GAC abzulegen, weiß ich nicht)



  • Leider funktioniert es bei mir weiterhin nicht, auch nicht wenn ich das .Net-Framework auf eine niedrigere Version setze (getestet: 2.0, 3.5, 4.6.2). Im Importdialog (Import Type Library) wird sie mir initial nicht angezeigt. Wenn ich sie dort händisch mit "Add" über die tlb hinzufüge (über die dll gibt immer "Fehler beim Laden der Typbibliothek/DLL") kommt anschließend bei "Class Names" Fehler beim Laden der Typbibliothek (wird aber nur grau angezeigt), gehe ich dennoch weiter (egal welche Option ich auswähle), liefert er mir spätestens beim Erzeugen der nötigen C++ Builder-Dateien ein "Error loading type library...".



  • Kannst du die TLB-Datei denn über den Type Library Explorer öffnen, s. Exploring Windows Type Libraries?



  • Th69 schrieb:

    Kannst du die TLB-Datei denn über den Type Library Explorer öffnen, s. Exploring Windows Type Libraries?

    Werde ich morgen nachprüfen, wäre zumindest ein Ansatzpunkt.
    Danke



  • Hallo zusammen,

    also ich verwende folgende Skripte:

    set TlbPath=.
    set BaseName=AteXls
    set TLB=%BaseName%.tlb
    
    REM del old tlb file
    if exist %TlbPath%\%TLB% del %TlbPath%\%TLB% && echo;%TlbPath%\%TLB% deleted
    
    REM generate new tlb file from dll
    echo;
    echo;Creating tlb file...
    call tlbexp.exe %TlbPath%\%BaseName%.dll
    
    if not exist .\tlb mkdir .\tlb && echo;.\tlb directory created
    
    echo;
    echo;Generating source files... 
    call tlibimp.exe -C -HpsActiveX -D%TlbPath%\tlb %TlbPath%\%TLB%
    

    Dieses Skript muß wegen Registry zugriffen als Admin laufen:

    set AssemblyPath=.
    set AssemblyBaseName=AteXls
    set AssemblyExtension=dll
    
    call regasm.exe %AssemblyPath%\%AssemblyBaseName%.%AssemblyExtension% /codebase
    

    Anschließend compiliere/linke ich die AteXls_TLB.cpp ins Projekt, und verwende es wie folgt:

    //template to use COM interface
    template <typename T>
    bool kcCreateInstance(T &comObj, const GUID &guid, String sName, TLog &L, String sPosition, bool bExcept=true)
    {
        HRESULT hRes = comObj.CreateInstance(guid);
        if(hRes != S_OK)
        {
            String sError;
            switch(hRes)
            {
                case S_OK:                      sError = "S_OK ";                    break;
                case REGDB_E_CLASSNOTREG:       sError = "REGDB_E_CLASSNOTREG ";     break;
                case CLASS_E_NOAGGREGATION:     sError = "CLASS_E_NOAGGREGATION ";   break;
                case E_NOINTERFACE:             sError = "E_NOINTERFACE ";           break;
                case E_OUTOFMEMORY:             sError = "E_OUTOFMEMORY";            break;
                case E_INVALIDARG:              sError = "E_INVALIDARG ";            break;
                default:                        sError = "Unknown ";                 break;
            }
    
            if(bExcept)
            {
                L.throwException(sPosition, L"Can not create COM connection to '%s'. CreateInstance(): %s (0x%lx)", sName.c_str(), sError.c_str(), hRes);
            }
            else
            {
                L.AddFmtFatalError(sPosition, L"Can not create COM connection to '%s'. CreateInstance(): %s (0x%lx)", sName.c_str(), sError.c_str(), hRes);
            }
    
            return false;
        }
        return true;
    }
    
    ...
    
    //mit COM interface verbinden wenn nötig
        CoInitialize(NULL);
        if(!Xls.IsBound())
        {
            kcCreateInstance<AteXls_Ptr>(Xls, CLSID_AteXls_, L"AteXls", L, POSITION);
        }
    

    Eventuell gab es noch Anpassungen (Compilerfehler) an dem aus der TLB generierten Code.

    Viel Erfolg.
    MfG Stephan



  • Th69 schrieb:

    Kannst du die TLB-Datei denn über den Type Library Explorer öffnen, s. Exploring Windows Type Libraries?

    Ja, zeigt mir auch alle Interfaces mit Methoden sowie die Klassen sauber an.



  • Stephan schrieb:

    ...

    Danke, ich werde im Laufe des Tages einen weiteren Test durchführen.