1

I'm facing a little trouble when trying to return an object (I'm also facing a problem when returning a class, but it is not the focus of the question, I'm just explaning because you may see commented errors in the code).

The aim of the code is to return a TMemo to be equalized to an existing object, something like that:

Memo1 = CriptLibDll::CriptLib::Encriptar(anyString, anyString, Memo1)

Here are the files:

CriptLib.h:

#ifndef CriptLibDllH
#define CriptLibDllH

#ifdef CRIPTNSDLL_EXPORTS
#define CRIPTLIBDLL_API __declspec(dllexport)
#else
#define CRIPTLIBDLL_API __declspec(dllimport)
#endif

#ifdef __cplusplus

#include <fmx.h>
#include <System.Classes.hpp>
#include <string.h>
#include <FMX.Memo.hpp>

extern "C" {
#endif

    CRIPTLIBDLL_API TMemo* Cript_BasicoM(String Original, String Chave, TMemo* Memo);
//  CRIPTLIBDLL_API TStringList Cript_BasicoL(String Original, String Chave, TSringList Lista);
    CRIPTLIBDLL_API String Cript_BasicoS(String Original, String Chave, String Linha);

#ifdef __cplusplus
}

namespace CriptLib
{
    class Encriptar
    {
    public:
        TMemo* Subst(String Original, String Chave, TMemo* Memo) { return Cript_BasicoM(Original, Chave, Memo); }
//      static TStringList Subst(String Original, String Chave, TSringList Lista) { return Cript_BasicoL(Original, Chave, Lista); }
        String Subst(String Original, String Chave, String Linha) { return Cript_BasicoS(Original, Chave, Linha); }
    };
}
#endif

#endif

CriptLib.cpp:

#define CRIPTNSDLL_EXPORTS

#include "CriptLib.h"

#include <fmx.h>
#include <FMX.Memo.hpp>
#include <System.Classes.hpp>
#include <string.h>

//---------------------------------------------------------------------------

TMemo* Cript_BasicoM(String Original, String Chave, TMemo* Memo){

    TMemo* Encriptado = Memo;

    if (Original.Length() != Chave.Length()) {
        throw Exception (L"O tamanho das palaras chave e original não podem ser diferentes");
    }

    String Linha = NULL;

    for (int i = 0; i < Original.Length(); i++) {
        for (int k = 0; k < Encriptado->Lines->Count; k++) {
            Linha = Encriptado->Lines->Strings[k];
            for (int l = 0; l < Linha.Length(); l++) {
                if (Linha[l] == Original[i]) Linha[l] = Chave [i];
            }
            Encriptado->Lines->Strings[k] = Linha;
        }
    }

    Encriptado->Lines->Add(Original);
    Encriptado->Lines->Add("CriptB");

    return Encriptado;
}

//---------------------------------------------------------------------------

/*TStringList Cript_BasicoL (String Original, String Chave, TStringList Lista){

    TStringList* Encriptado = new TStringList;
    Encriptado->Strings = Lista->Strings;

    if (Original.Length() != Chave.Length()) {
        throw Exception (L"O tamanho das palaras chave e original não podem ser diferentes");
    }

    String Linha = NULL;

    for (int i = 0; i < Original.Length(); i++) {
        for (int k = 0; k < Encriptado->Count; k++) {
            Linha = Encriptado->Strings[k];
            for (int l = 0; l < Linha.Length(); l++) {
                if (Linha[l] == Original[i]) Linha[l] = Chave [i];
            }
            Encriptado->Strings[k] = Linha;
        }
    }

    Encriptado->Add(Original);
    Encriptado->Add("CriptB");

    return Encriptado;
} */

//---------------------------------------------------------------------------

String Cript_BasicoS (String Original, String Chave, String Linha){

    String Encriptado = Linha;

    if (Original.Length() != Chave.Length()) {
        throw Exception (L"O tamanho das palaras chave e original não podem ser diferentes");
    }

    for (int i = 0; i < Original.Length(); i++) {
        for (int l = 0; l < Encriptado.Length(); l++) {
            if (Encriptado[l] == Original[i]) Encriptado[l] = Chave [i];
        }
    }

    return Encriptado;
}
//---------------------------------------------------------------------------

Errors I've gotten untill now:

[ilink32 Error] Error: Unresolved external '__fastcall System::Internal::Strhlpr::UnicodeFree(System::UnicodeString&)' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|ustring

[ilink32 Error] Error: Unresolved external '__fastcall System::Syncobjs::TInterlocked::Increment(int&)' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|ustring

[ilink32 Error] Error: Unresolved external '__fastcall System::Internal::Strhlpr::UnicodeAssign(System::UnicodeString&, System::UnicodeString&)' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|ustring

[ilink32 Error] Error: Unresolved external '__fastcall System::Internal::Strhlpr::UnicodeSetLength(System::UnicodeString&, int)' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|ustring

[ilink32 Error] Error: Unresolved external 'System::Sysutils::Exception::' referenced from C:\USERS\USER\DOCUMENTS\DESENVOLVIMENTO BASE\TT2\WIN32\DEBUG\CRIPTLIB.OBJ

[ilink32 Error] Error: Unresolved external '__fastcall System::Sysutils::Exception::Exception(System::UnicodeString)' referenced from C:\USERS\USER\DOCUMENTS\DESENVOLVIMENTO BASE\TT2\WIN32\DEBUG\CRIPTLIB.OBJ

[ilink32 Error] Error: Unresolved external '__fastcall System::Sysutils::Exception::~Exception()' referenced from C:\USERS\USER\DOCUMENTS\DESENVOLVIMENTO BASE\TT2\WIN32\DEBUG\CRIPTLIB.OBJ

[ilink32 Error] Error: Unresolved external '__fastcall System::TObject::~TObject()' referenced from C:\USERS\USER\DOCUMENTS\DESENVOLVIMENTO BASE\TT2\WIN32\DEBUG\CRIPTLIB.OBJ

[ilink32 Error] Error: Unresolved external System::Sysconst::_SRangeError' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|ustring

[ilink32 Error] Error: Unresolved external '__fastcall System::LoadResString(System::TResStringRec *)' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|syssupp

[ilink32 Error] Error: Unresolved external 'System::Sysutils::ERangeError::' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|ustring

[ilink32 Error] Error: Unresolved external '__fastcall System::UniqueString(System::UnicodeString&)' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|ustring

[ilink32 Error] Error: Unresolved external '__fastcall System::Internal::Strhlpr::UnicodeFromPChar(System::UnicodeString&,char *, bool)' referenced from C:\PROGRAM FILES(X86)\EMBARCADERO\STUDIO\15.0\LIB\WIN32\DEBUG\VCLE.LIB|ustring

[ilink32 Error] Error: Unable to perform link

References used to (try) to build this project:

How to “return an object” in C++?

C++ return a class object by reference

Fill a TStringList in a DLL (unfortunately Delphi)

Since now, Thanks A LOT

Community
  • 1
  • 1
mauroaraujo
  • 332
  • 1
  • 10
  • 23
  • 1
    It is not safe to pass non-POD data over the DLL boundary like this. To implement this function in a safe manner, you would have to take an array of raw character strings as input, and return an array of raw character strings as output. Don't involve the UI directly, let the caller decide how to handle the UI outside of the DLL. If you intend to pass VCL objects over the DLL boundary, you MUST create a Package instead of a DLL, and enable Runtime Packages in both your Package and EXE projects. Even then, you should not pass a `TMemo` itself, you should pass a `TStrings` instead. – Remy Lebeau Dec 07 '15 at 19:29
  • So, is the structure itself correct? I also have to create and return a pointer? Because I've seen TStrings is not a "main component", it is like a subclass called by other objects. So, I also tried to use TStringList. However, more errors happened. – mauroaraujo Dec 07 '15 at 22:32
  • 1
    The structure itself is not safe unless you create a Package instead of a DLL. Period. That is necessary for interacting with RTL objects across the DLL boundary. As for `TStrings`, the `TMemo.Lines` property is a `TStrings`-derived object, so you can pass the `Lines` to the function instead of passing the `TMemo` itself. Also, there is no reason to `return` the same object that is being passed in. The function is modifying the object directly (which is why Packages are important), not making a copy of it. – Remy Lebeau Dec 07 '15 at 23:11
  • So, can I return a TStrings itself? Or I need to return something like a TStringList? And I see your point about the necessity of create a new package, but the only thing important for me for a while is actually to return the strings in TMemo modified, so I was trying to copy the object and return it. Thank you for opening my eyes! Now I just have the doubt above XD – mauroaraujo Dec 08 '15 at 02:46
  • 1
    You *can* return a new `TStrings`-derived object (like `TStringList`), but only if you are implementing a Package instead of a DLL. I can't stress this enough, you cannot skip this step and expect your app to operate correctly. In any case, you are not copying anything, you are modifying the Memo directly, so there is no reason to return anything. If you want to return a copy of the Memo without modifying it, you should pass in separate input and output `TStrings` objects, and let the function copy values from one to the other as needed. – Remy Lebeau Dec 08 '15 at 03:07
  • Thank you a LOT, I'm going to try it. Is there a way to close this topic? – mauroaraujo Dec 08 '15 at 11:04

0 Answers0