Poprawne DLL dla Delphi napisane w C++

2

Chciałbym funkcje w C++ uruchomić w Delphi
Kompilator mingw-w64-i686-gcc

Po stronie C++

#pragma pack(push)
#pragma pack(1)

.....
int PWD_2a_(....)
.....


// H-file
 #ifdef __cplusplus 
extern "C" {
#endif
    int PWD_2a(PWD_2a_params *pwd_2a_params);
#ifdef __cplusplus 
}
#endif
#pragma pack(pop)

// CPP-file 
int PWD_2a(PWD_2a_params *pwd_2a_params)
{
  
  return PWD_2a_(   pwd_2a_params.field1,  pwd_2a_params.field2   );
}
 PWD_2a_params = packed record
    struct1 field1;
    struct2 field2;
    ...
 end;
 Tproc_PWD_2a = function(var params: PWD_2a_params): Integer; cdecl;
 proc_PWD_2a: Tproc_PWD_2a;
 proc_PWD_2a :=  GetProcAddress(dll_Handle_PWD_2a, 'PWD_2a');

I z nieznanych powodów Delphi "czasami" nie potrafi uruchomić takiej funkcji:

napisałem "czasami" bo

int PWD_2a(PWD_2a_params *pwd_2a_params)
{
  printf("%d", pwd_2a_params.fielld1.pole1 );
  return PWD_2a_(   pwd_2a_params.field1,  pwd_2a_params.field2   );
}

tak się NIE uruchamia po stronie Delphi (CALL NULL)
screenshot-20220930214608.png

a taki kod c++ skompilowany d0 DLL dziala poprawnie
int PWD_2a(PWD_2a_params *pwd_2a_params)
{
  // printf("%d", pwd_2a_params.fielld1.pole1 );
  return PWD_2a_(   pwd_2a_params.field1,  pwd_2a_params.field2   );
}

screenshot-20220930215954.png

po stronie C++ i Delphi struktura ma taki sam rozmiar 144B

DLL w aplikacji C++ dziala zawsze poprawnie !

4

Nie musi być koniecznie stdcall. Musi być ta sama konwencja po obu stronach. C++ ma domyślnie cdecl, i tak podano w Delphi.

Wygląda że w drugim przypadku GetProcAddress zwraca nil, więc to nie jest problem z wywołaniem, tylko znalezieniem funkcji.

Pytanie, w jaki sposób ta funkcja jest eksportowana w C++? Nie widać żadnego dllexport czy coś.

0

@Azarien poszedłem tym tropem , doczytam LOG i jest problem z LoadLibrary

jak w c++ funkcja ma taką treść <<wersja 1>>

int PWD_2a(PWD_2a_params *pwd_2a_params)
{
  // printf("%d", pwd_2a_params.fielld1.pole1 );
  return PWD_2a_(   pwd_2a_params.field1,  pwd_2a_params.field2   );
}

LoadLibrary zwraca poprawną wartość

a jak jest od komentuje <<wersja 2>>

int PWD_2a(PWD_2a_params *pwd_2a_params)
{
  printf("%d", pwd_2a_params.fielld1.pole1 );
  return PWD_2a_(   pwd_2a_params.field1,  pwd_2a_params.field2   );
}

to LoadLibrary zwraca "0", żadnych innych różnic

Robie tak:
zmieniam linie z printf(...) przelaczam <<wersja 1>> / <<wersja 2>>
buduje DLL
testuje w Delphi czy dziala

czy problemem moze byc np. uzyta biblioteka FFTW ?

Bo w sumie nie robie nic czego bym wcześniej nie robił i zawsze działało , albo umyka mi jakis szczegół

0

Czyli do DLL nie trafia ten printf()?

0

Dla wersji "2" LoadLibrary zwraca 0 , a SysErrorMessage(GetLastError) zwraca "Nie mozna odnalezc okreslonej procedury"
Kompunikaty event log w Delphi

Module Load: libpwd.dll. ...
Module Load: libfftw3-3.dll. ...
Module Unload: libfftw3-3.dll....
Module Unload: libpwd.dll....

Dla wersji "1"

Module Load: libpwd.dll. ...
Module Load: libfftw3-3.dll. ...

W sumie to nie nie ma znaczenia czy uzyje printf czy jakąś inna funkcję

0

I jeszcze dwa pliki z programu "dumpbin.exe" /exports <dll>"
export1.txtexport2.txt

interesuje mnie w delphi tylko jedna funkcja PWD_2a

0

Może spróbuj zamienić cdecl w paskalu na stdcall w C.

0

Chciałbym funkcje w C++ uruchomić w Delphi
Kompilator mingw-w64-i686-gcc

Zaraz zaraz. Bo cały czas miałem w głowie że używasz Visual C++.

Czy nie jest tak, że użycie printf() albo innej funkcji z biblioteki standardowej powoduje dodanie zależności w postaci dodatkowej dll-ki z biblioteką standardową tego mingwa?
I jeśli ścieżki do tej biblioteki nie masz w PATH albo lokalnie to ci się LoadLibrary nie uda.

Czy plik .exe, skompilowany tym samym kompilatorem C++ a odpalający printf(), umieszczony w katalogu z programem w Delphi uruchamia się? Czy może krzyczy o brak jakiejś DLL-ki.

0

Hmm tak sobie myślałem o flagach jakie są ustawione i domyślnie LoadLibraryA ma flagę DONT_RESOLVE_DLL_REFERENCES musiałbyś odpalić LoadLibraryExA i ustawić flagę LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, wtedy program znajdzie libc.dll i odpali ci tego printfa.

Jakbyś nie miał tam żadnych referencji do rozwiązania, możesz tą bibliotekę wczytać jak plik do pamięci w region executable dodać do tego offset twojej funkcji i zrzutować na pointer na funkcję będzie pięknie hulać na produkcji :>

0

Poszedłem tym tropem
https://stackoverflow.com/questions/6154600/loadlibrary-fails-getlasterror-no-help

w programie gflags.exe zaznaczyłem:

screenshot-20221002125248.png

4260:5468 @ 13147312 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlDeleteCriticalSection" by name
4260:5468 @ 13147312 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlEnterCriticalSection" by name
4260:5468 @ 13147312 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlInitializeCriticalSection" by name
4260:5468 @ 13147328 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlLeaveCriticalSection" by name
4260:5468 @ 13147328 - LdrpNameToOrdinal - WARNING: Procedure "_ZNSt7__cxx1119basic_ostringstreamIcSt11char_traitsIcESaIcEEC1Ev" could not be located in DLL at base 0x10AB0000.
4260:5468 @ 13147328 - LdrpReportError - ERROR: Locating export "_ZNSt7__cxx1119basic_ostringstreamIcSt11char_traitsIcESaIcEEC1Ev" for DLL "D:\delphi\USG_USB\U32\bin\lib\labview\PWD_2a\libpwd.dll" failed with status: 0xc0000139.
4260:5468 @ 13147343 - LdrpProcessWork - ERROR: Unable to load DLL: "libpwd.dll", Parent Module: "(null)", Status: 0xc0000139

Namieszałem z zależnościami DLL

1 użytkowników online, w tym zalogowanych: 0, gości: 1