Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi C++ Dll (https://www.delphipraxis.net/199502-delphi-c-dll.html)

mandoza 27. Jan 2019 22:57

Delphi-Version: 10.2 Tokyo

Delphi C++ Dll
 
Hello every one ; I've a C++ DLL that i want to consume from Delphi Project ; My C++ part is

Delphi-Quellcode:
//Header file UserIdentity.h
extern "C" {
#endif
struct UserIdentity
{
    const char* name;
    int id;
};
/**
 * Gets all of the UserIdentity objects currently available.
 * @param[out] pCount A pointer to storage for the number of UserIdentity objects available
 * @param[out] pUserIdentities A pointer to storage for a number of UserIdentity objects indicated by pCount
 *  \n NOTE : Pass nullptr for pUserIdentities to get only the count value
 * @usage
 *
 *  size_t userIdentitiesCount = 0;
 *  UserIdentity* userIdentities = nullptr;
 *  Ui_export(&userIdentitiesCount, nullptr);
 *  if (userIdentitiesCount) {
 *      userIdentities = new UserIdentity[userIdentitiesCount];
 *      Ui_export(&userIdentitiesCount, userIdentities);
 *      // Process userIdentities...
 *      delete [] userIdentities;
 *  }
 *
 */
EXAMPLE_LIBRARY_EXPORT void Ui_export(size_t* pCount, UserIdentity* pUserIdentities);
#ifdef __cplusplus
}
#endif
And here's my cpp fie " UserIdentity.cpp "

Delphi-Quellcode:
#include "UserIdentity.h"
#include <map>
static const std::map<std::string, int> gUserIdentites = {
    { "Bob", 100 },
    { "Jone", 101 },
    { "Alice", 102 },
    { "Doe", 103 }
};
void Ui_export(size_t* pCount, UserIdentity* pUserIdentities)
{
    // NOTE : If pCount is a valid pointer then we'll set pCount...
    if (pCount) {
        *pCount = gUserIdentites.size();
    }
    // NOTE : If pUserIdentities is a valid pointer then we'll populate it with
    //  data...it's the resposibility of the caller to ensure they've correctly
    //  gotten the count and have allocated enough storage for the data...
    if (pUserIdentities) {
        size_t i = 0;
        for (const auto& userIdentity : gUserIdentites) {
            // NOTE : Becuase we're getting a C string using the key's c_str()
            //  method we need to make sure that we document cases which will
            //  cause map elements to become invalidated.
            //  The API could be made more robust by having allocators for
            //  dynamic strings, but this would introduce complexity that may
            //  not be necessary.
            pUserIdentities[i].name = userIdentity.first.c_str();
            pUserIdentities[i].id = userIdentity.second;
            ++i;
        }
    }
}
Finally my Delphi attempt part :
Delphi-Quellcode:
Type
UserIdentity = record
    name_ : PAnsiChar;
    id : Integer;
  end;
  PUserIdentity = ^UserIdentity;
procedure Ui_export(pCount : PUInt32; pUserIdentities : PUserIdentity);cdecl; external Cdllname;
....
procedure TForm39.Button24Click(Sender: TObject);
var
  pCount : UInt32;
  LUserEntity : PUserIdentity;
  LUserEntityData : UserIdentity;
  i: Integer;
begin
  Ui_export(@pCount, nil);
  GetMem(LUserEntity, pCount);
  Ui_export(@pCount, LUserEntity);
  for i := 0 to pCount - 1 do
  begin
    memo1.Lines.Add(LUserEntity^.name_+' '+LUserEntity^.id.ToString);
    Inc(LUserEntity);
  end;
end;
The issue with delphi is that i get the 2 first values correctly that's :
Bob
Jone

But for
Alice i get some rubbishes value which is ' yyyyyyyyyyyyyyyyyyyyyyy'

for
Doe
i get it's correct value .

So please is there any incorrect part in my Delphi Implementation ?

Klaus01 28. Jan 2019 07:11

AW: Delphi C++ Dll
 
Hi,

will it make a difference when using a packet record instead the unpacked one?

Delphi-Quellcode:
UserIdentity = packet record
    name_ : PAnsiChar;
    id : Integer;
  end;
Best regards
Klaus

Zacherl 28. Jan 2019 08:22

AW: Delphi C++ Dll
 
size_t is a plaform and architecture specific type ... using UInt32 might not be correct e.g. for 64-bit. The real problem is this part tho:
Delphi-Quellcode:
GetMem(LUserEntity, pCount);
It has to be
Delphi-Quellcode:
GetMem(LUserEntity, pCount * SizeOf(UserEntity));

Der schöne Günther 28. Jan 2019 08:36

AW: Delphi C++ Dll
 
Why even multiply with `count`? The size of the struct is always the same. It only contains a pointer, not the characters themselves.

Zacherl 28. Jan 2019 08:48

AW: Delphi C++ Dll
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1424283)
Why even multiply with `count`? The size of the struct is always the same. It only contains a pointer, not the characters themselves.

Nope. It fills the memory described by the pointer with the list elements. In C/C++
Delphi-Quellcode:
int*
is basically the same as
Delphi-Quellcode:
int[]
. The struct size is ofc. the same, but the number of elements in the array might be different each time, so you have to alloc enough space to prevent buffer overrides (thats what happening without the *count).

Der schöne Günther 28. Jan 2019 09:19

AW: Delphi C++ Dll
 
My bad, I did not read properly. I thought "count" was referring to the number of characters in the string, not the number of structs returned.

mandoza 28. Jan 2019 10:28

AW: Delphi C++ Dll
 
Zitat:

Zitat von Zacherl (Beitrag 1424282)
size_t is a plaform and architecture specific type ... using UInt32 might not be correct e.g. for 64-bit. The real problem is this part tho:
Delphi-Quellcode:
GetMem(LUserEntity, pCount);
It has to be
Delphi-Quellcode:
GetMem(LUserEntity, pCount * SizeOf(UserEntity));

Thank you Zacherl , I've fixed the issue by using string fixed length in both C++ and Delphi , and using the UIntPtr instead of UInt32

Again thank you .


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:06 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