Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

176
Visualizações
Importing a C# .NET 6.0 Core Dll into a C++ without TLB file

I have quite a number of C# Dlls that were made in .NET 4.6 Framework and need to get upgraded to .NET Core 6 - that part is relatively straightforward. However, this library ALSO is used within a C++ application, via COM Interop. This option was relatively straightforward in .NET 4.6, because at build time there was an option to expose to COM Interop. This created a .tlb file, which could be imported directly into the C++ app. All of the necessary marshalling was done within the C# code - arrays were passed as SafeArrays, etc. (See example below). Regasm.exe was run after the fact to register the necessary C# code.

With the upgrade to .NET Core 6, the ability to create a .tlb file at runtime was lost. However, (apparently) interoperability should be straightforward. I have seen Nuget packages like DllExport (which has unclear examples for SafeArrays). I've read page after page of Microsoft's references on COM interop and COM hosting, and read relative examples. I briefly looked into the rabbit hole of building my own .tlb file. I've seen many custom examples that do not extend to this exact issue.

Here is some of the code that I am trying to hook together, as an example for you. What kind of changes would I go about making?

C# Code to import

    public void CSharpMacro(
                                        [MarshalAs(UnmanagedType.SafeArray)] double[] D,
                                        [MarshalAs(UnmanagedType.SafeArray)] double[] O,
                                        [MarshalAs(UnmanagedType.SafeArray)] double[] H,
                                        [MarshalAs(UnmanagedType.SafeArray)] double[] L,
                                        [MarshalAs(UnmanagedType.SafeArray)] double[] C,
                                        [MarshalAs(UnmanagedType.SafeArray)] double[] V,
                                        [MarshalAs(UnmanagedType.LPStr)] string FilePath,
                                        [MarshalAs(UnmanagedType.SafeArray)] ref double[] sOutput,
                                        [MarshalAs(UnmanagedType.I8)] long CustNum,
                                        [MarshalAs(UnmanagedType.R8)] double TSDate)
        {

            String path = @"...\Errors.txt";
            try
            {
                //some code
            }
            catch (Exception e)
            {
                //error handling
            }
        }

C++ Importing Example (current method) - Please note, this is a lot of code but the purpose is to show you how the .tlb is imported and how the method from C# is used within the code, and some of what goes on around that, like the use of SafeArrays:

// In the below import statement, use the location of the Release version of your C# DLL 
#import "...\PSP_CSLibrary.tlb" no_namespace

//later in the code... (EasyObject is from external library, don't worry about it)
void far __declspec(dllexport) __stdcall UMacro(EasyObject* pELObj, char* path)
{

    // Initialize the COM interface
    HRESULT hr = CoInitialize(NULL);
    try
    {
        if (SUCCEEDED(hr) && pELObj != NULL)
        {
            // Init pointer to C# Library
            PSP_CSLibraryDLLClassPtr p(__uuidof(PSP_CSLibrary));
            if (p != NULL)
            {
                int datanumber = 1;
                double *dOutput = new double[100];
                for (int j = 0; j < 100; j++) dOutput[j] = 0;
                SAFEARRAY* sOutput = doubleToSA(dOutput, 100);
                EN_DATA_STREAM datastream = (datanumber == 1) ? pELObj->DataStream : GetDataStream(datanumber);
                double TSDate = pELObj->DateTimeMD[datastream]->AsDateTime[0];
                long CustomerNumber = pELObj->Platform->CustomerID;
                int length = pELObj->CloseMD[datastream]->BarsBack;
                if (length > 0)
                {
                    double *dDate = new double[length];
                    double *dOpen = new double[length];
                    double *dHigh = new double[length];
                    double *dLow = new double[length];
                    double *dClose = new double[length];
                    double *dVolume = new double[length];
                    // Load the double arrays with LEAST recent 0
                    for (int i = 0; i < length; i++)
                    {
                        dVolume[length - i - 1]     = pELObj->VolumeMD[datastream]->AsDouble[i];
                        dOpen[length - i - 1]       = pELObj->OpenMD[datastream]->AsDouble[i];
                        dHigh[length - i - 1]       = pELObj->HighMD[datastream]->AsDouble[i];
                        dLow[length - i - 1]        = pELObj->LowMD[datastream]->AsDouble[i];
                        dClose[length - i - 1]      = pELObj->CloseMD[datastream]->AsDouble[i];
                        dDate[length - i - 1]       = pELObj->DateTimeMD[datastream]->AsDateTime[i];
                    }
                    // Convert to safe arrays from double arrays
                    SAFEARRAY* sVolume = doubleToSA(dVolume, length);
                    SAFEARRAY* sHigh = doubleToSA(dHigh, length);
                    SAFEARRAY* sOpen = doubleToSA(dOpen, length);
                    SAFEARRAY* sLow = doubleToSA(dLow, length);
                    SAFEARRAY* sClose = doubleToSA(dClose, length);
                    SAFEARRAY* sDate = doubleToSA(dDate, length);


/////IMPORTANT PART
                    if (sOpen != nullptr && sHigh != nullptr && sLow != nullptr && sOutput != nullptr && p != nullptr &&  sClose != nullptr && dOutput != nullptr)
                    {
                        p->CSharpMacro(sDate, sOpen, sHigh, sLow, sClose, sVolume, path, &sOutput, CustomerNumber, TSDate);
                    }

/////
                    // Release memory
                    if (sDate != nullptr)   SafeArrayDestroy(sDate);
                    if (sVolume != nullptr) SafeArrayDestroy(sVolume);
                    if (sOpen != nullptr)   SafeArrayDestroy(sOpen);
                    if (sHigh != nullptr)   SafeArrayDestroy(sHigh);
                    if (sLow != nullptr)    SafeArrayDestroy(sLow);
                    if (sClose != nullptr)  SafeArrayDestroy(sClose);
                    if (sOutput != nullptr) SafeArrayDestroy(sOutput);
                    if (dDate != nullptr)   delete[] dDate;
                    if (dVolume != nullptr) delete[] dVolume;
                    if (dOpen != nullptr)   delete[] dOpen;
                    if (dHigh != nullptr)   delete[] dHigh;
                    if (dLow != nullptr)    delete[] dLow;
                    if (dClose != nullptr)  delete[] dClose;
                    if (dOutput != nullptr) delete[] dOutput;
                }
            }
            p->Release();
        }

    }
    catch (exception &e)
    {
        // did we get it?
        string out_ = "UMacro error= ";
        std::ostringstream strs;
        strs << e.what();
        std::string str = strs.str();
        out_ += str;
        appendLineToFile("PSP_Interface_Errors.txt", out_);
    }
    CoUninitialize();
    return;
}

This interaction, as shown above, works. Does anyone have ANY insight on how to continue to link up these two but with the C# in .NET Core 6? Preferably with minimal effort. I would like to think most of the work is already done, since types ARE marshalled as you can see. How do I import a C# Dll now, without a tlb file?

Edit: as a note, this must be in unmanaged C++. I am currently investigating using a C++/CLR interface layer, and have gotten moderate success. Will update if successful.

over 4 years ago · Santiago Trujillo
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda