Zeleo bih da iz dll-a koji je napravljen u C++ Builder-u(Version 5) izvucem neke metode ali mi bas ne ide?!? Takodje covek koji je napravio taj dll ne moze da koristi moj dll (napravljen u Delphi-u). Naravno on opusteno radi sa svojim dll-om bez ikakvih problema i ja sa svojim. Zna li neko u cemu je tajna? koristili smo standardne tipove tako da neverujem da je u tome problem. Naime u C++ dll-u postoji funkcija koja ne prima nikakve parametre a vraca string (AnsiString).
Problem sa dll-ovima
Zaključano
Zakačeno
Ne bi trebalo biti problema ukoliko su procedure definirane kao stdcall
i string parametre koje ulaze ili izlaze budu pchar (pointer to null terminated string)
i string parametre koje ulaze ili izlaze budu pchar (pointer to null terminated string)
Potpis
People who think they know everything tend to irritate those of us who do.
Uspeo sam da izvucem funkciju iz C++ dll-a ali sad imam drugi problem:
funkcija je uspesno odradjena, vraca vrednost koju treba ali se ceo program zapuca nakon zavrsetka rada sa dll-om. Dll izgleda ovako:
#include <vcl.h>
#pragma hdrstop
#include "DLLUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TDLLForm *DLLForm;
//---------------------------------------------------------------------------
__fastcall TDLLForm::TDLLForm(TComponent* Owner)
: TForm(Owner)
{
name = "No chosen name.";
}
//---------------------------------------------------------------------------
AnsiString __fastcall TDLLForm::GetName()
{
return name;
}
//---------------------------------------------------------------------------
void __fastcall TDLLForm::FirstNameButtonClick(TObject *Sender)
{
name = "Ime.";
Close();
}
//---------------------------------------------------------------------------
void __fastcall TDLLForm::LastNameButtonClick(TObject *Sender)
{
name = "Prezime.";
Close();
}
//---------------------------------------------------------------------------
//Exported function
AnsiString ChooseName()
{
AnsiString name;
TDLLForm* DLLForm = new TDLLForm(NULL);
DLLForm->ShowModal();
name = DLLForm->GetName();
delete DLLForm;
return name;
}
//---------------------------------------------------------------------------
i kazem funkcija vrati odgovarajucu vrednost koja nazalost nikad ne stigne da se prikaze na Delphi formi (neki EditBox ili Label ) zato sto se program zapuca?!?
funkcija je uspesno odradjena, vraca vrednost koju treba ali se ceo program zapuca nakon zavrsetka rada sa dll-om. Dll izgleda ovako:
#include <vcl.h>
#pragma hdrstop
#include "DLLUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TDLLForm *DLLForm;
//---------------------------------------------------------------------------
__fastcall TDLLForm::TDLLForm(TComponent* Owner)
: TForm(Owner)
{
name = "No chosen name.";
}
//---------------------------------------------------------------------------
AnsiString __fastcall TDLLForm::GetName()
{
return name;
}
//---------------------------------------------------------------------------
void __fastcall TDLLForm::FirstNameButtonClick(TObject *Sender)
{
name = "Ime.";
Close();
}
//---------------------------------------------------------------------------
void __fastcall TDLLForm::LastNameButtonClick(TObject *Sender)
{
name = "Prezime.";
Close();
}
//---------------------------------------------------------------------------
//Exported function
AnsiString ChooseName()
{
AnsiString name;
TDLLForm* DLLForm = new TDLLForm(NULL);
DLLForm->ShowModal();
name = DLLForm->GetName();
delete DLLForm;
return name;
}
//---------------------------------------------------------------------------
i kazem funkcija vrati odgovarajucu vrednost koja nazalost nikad ne stigne da se prikaze na Delphi formi (neki EditBox ili Label ) zato sto se program zapuca?!?
a da postujes delphi kod iz kojeg zoves dll ?
i nadam se da si video ono sto sam pisao .... ali ipak da ponovim stdcall !!!
stdcall dll-ovi mogu da se koriste iz VB,Delphi,C++ itn ...
a mozes i explicitno pozvati destruktor objekta pre nego obrises pointer
( jest da se destruktori sami pozivaju ali tako ces biti siguran da to ne zapucava program
)
i nadam se da si video ono sto sam pisao .... ali ipak da ponovim stdcall !!!
stdcall dll-ovi mogu da se koriste iz VB,Delphi,C++ itn ...
a mozes i explicitno pozvati destruktor objekta pre nego obrises pointer
( jest da se destruktori sami pozivaju ali tako ces biti siguran da to ne zapucava program
Potpis
People who think they know everything tend to irritate those of us who do.
Greska je bila u tome sto dll funkcija napisana u C++-u nije bila deklarisana kao stdcall. Kada je to prepravljeno sve radi kako treba. Ali...
Evo u cemu je stvar:
u Delphi-ju deklaracija izgleda otprilike ovako:
Function ChooseName():String;stdcall;external 'cdll.dll' name 'ChooseName';
i onda poziv otprilike:
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption:=ChooseName();
end;
Nakon klika na dugme Button1 pojavljuje se formica iz dll-a i u zavisnosti od toga sta je odabrano dodeljuje label-u odgovarajuci string. Problem se sad javlja kad se dugme pritisne vise puta. Naime nakon izbora u dll formi, ta forma nestaje ,a label u delphi formi dobije svoj string ali ako to pokusam nekoliko puta da uradim program se zapuca (pa nekad cak i ceo racunar, plavi ekran itd.) ,a javlja poruke tipa: out of memory,illegal operation,problem sa kenel32.dll,problem sa vcl50.dll... sve zavisi. Mislim da su u pitanju objekti koji se kreiraju pozivom dll-a (forma i tri dugmeta kao i lokalne promenljive),a ostaju na steku po zavrsetku rada sa dll-om i niko ih ne unisti (samo pretpostavka), stoga bi mogao malo da pojasnis onaj deo tvoje poruke o pozivanju destruktora i eksplicitnom unistavanju objekata. I ej, hvala na pomoci :).
Evo u cemu je stvar:
u Delphi-ju deklaracija izgleda otprilike ovako:
Function ChooseName():String;stdcall;external 'cdll.dll' name 'ChooseName';
i onda poziv otprilike:
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption:=ChooseName();
end;
Nakon klika na dugme Button1 pojavljuje se formica iz dll-a i u zavisnosti od toga sta je odabrano dodeljuje label-u odgovarajuci string. Problem se sad javlja kad se dugme pritisne vise puta. Naime nakon izbora u dll formi, ta forma nestaje ,a label u delphi formi dobije svoj string ali ako to pokusam nekoliko puta da uradim program se zapuca (pa nekad cak i ceo racunar, plavi ekran itd.) ,a javlja poruke tipa: out of memory,illegal operation,problem sa kenel32.dll,problem sa vcl50.dll... sve zavisi. Mislim da su u pitanju objekti koji se kreiraju pozivom dll-a (forma i tri dugmeta kao i lokalne promenljive),a ostaju na steku po zavrsetku rada sa dll-om i niko ih ne unisti (samo pretpostavka), stoga bi mogao malo da pojasnis onaj deo tvoje poruke o pozivanju destruktora i eksplicitnom unistavanju objekata. I ej, hvala na pomoci :).
Jos nigde nisam video kako exportujes funkciju iz Cbuildera,
i najverovatnije to je exportuje kao cdecl a ne stdcall,
kao sto si rekao prvi put se funkcija izvrsi a drugi put nece.
to je zato sto ti je pozivas kao stdcall, a funkcija je najverovatnije exportirana
nesto slicno ovome:
kod stdcall rutina sama skida parametre sa steka, a kod cdecl proces koji poziva funkciju mora iscistiti stek. bas zbog toga prvi put sve prodje a drug put popuca.
Umesto ansistring declariraj funkcije kao char*, a kad iz zoves pozovi ih ovako:
Ali ako si vec promenio export da bude stdcall onda si zavrsio pola posla,
samo ti jos treba da parametri koje vracaju ili primaju budu char* a iz delphija da ih zoves kao PChar :) To sto sam pomenu o pozivanju destruktora ne treba ti,
posto kad obrises pointer C++ sam pozove destruktor, ali ako toliko hoces mozes i to da probas ovako:
.....
DLLForm->Free(); // pozovi destruktor objekta
delete DLLForm; // pa onda obrisi pointer
...
Ali naci ces puno textova gde pise da to NE VALJA ! da kad pozoves delete na pointer, on sam izvrsi destruktor objekta
pozdrav
i najverovatnije to je exportuje kao cdecl a ne stdcall,
kao sto si rekao prvi put se funkcija izvrsi a drugi put nece.
to je zato sto ti je pozivas kao stdcall, a funkcija je najverovatnije exportirana
nesto slicno ovome:
Code:
extern "C" AnsiString __declspec (dllexport) ChooseName();
extern "C" AnsiString __declspec (dllexport) ChooseName();
kod stdcall rutina sama skida parametre sa steka, a kod cdecl proces koji poziva funkciju mora iscistiti stek. bas zbog toga prvi put sve prodje a drug put popuca.
Umesto ansistring declariraj funkcije kao char*, a kad iz zoves pozovi ih ovako:
Code:
Function ChooseName():Pchar;cdecl;external 'cdll.dll' name 'ChooseName';
Function ChooseName():Pchar;cdecl;external 'cdll.dll' name 'ChooseName';
Ali ako si vec promenio export da bude stdcall onda si zavrsio pola posla,
samo ti jos treba da parametri koje vracaju ili primaju budu char* a iz delphija da ih zoves kao PChar :) To sto sam pomenu o pozivanju destruktora ne treba ti,
posto kad obrises pointer C++ sam pozove destruktor, ali ako toliko hoces mozes i to da probas ovako:
.....
DLLForm->Free(); // pozovi destruktor objekta
delete DLLForm; // pa onda obrisi pointer
...
Ali naci ces puno textova gde pise da to NE VALJA ! da kad pozoves delete na pointer, on sam izvrsi destruktor objekta
pozdrav
Potpis
People who think they know everything tend to irritate those of us who do.
Funkcija se iz Builder-a exportuje kao stdcall (napomenuo sam da je to bila greska ali je ispravljeno) ,a i poziva se u Delphiju kao stdcall. Medjutim nisam probao da odradim celu stvar sa Pchar tipom. Probacu pa cu javiti.
Riste, ja sam onaj "covek koji je napravio C++ dll" (citiram Plamenka)
Hvala na savetu za __stdcall, odn. cdecl...
Kazi mi samo zasto insistiras na PChar tj. char* umesto AnsiString-a, odn. zar ne
moze da ostane AnsiString ali da ukljucim u CBuilder dll projekat i memmgr.lib
(bar tako pise pri startovanju DllWizard-a)?
Jeste da bi tada i onaj ko koristi dll to isto morao da uradi, ali me interesuju mogucnosti...
Hvala na savetu za __stdcall, odn. cdecl...
Kazi mi samo zasto insistiras na PChar tj. char* umesto AnsiString-a, odn. zar ne
moze da ostane AnsiString ali da ukljucim u CBuilder dll projekat i memmgr.lib
(bar tako pise pri startovanju DllWizard-a)?
Jeste da bi tada i onaj ko koristi dll to isto morao da uradi, ali me interesuju mogucnosti...
Mozda bi to moglo da radi sa borlandovim memory menagerom, ali nikad nisam
probao to uraditi iz CB5 i prebaciti u delphi i kako bi to radilo pojma nemam, hteo sam, samo da profunkcionira stvar sa BCB dll importa u delphi, a kombinacija sa char* i Pchar je SIGURNO resenje. Ukoliko uspete da to proradite sa AnsiString, onda postujte tips&tricks
Keep on the good work
probao to uraditi iz CB5 i prebaciti u delphi i kako bi to radilo pojma nemam, hteo sam, samo da profunkcionira stvar sa BCB dll importa u delphi, a kombinacija sa char* i Pchar je SIGURNO resenje. Ukoliko uspete da to proradite sa AnsiString, onda postujte tips&tricks
Keep on the good work
Potpis
People who think they know everything tend to irritate those of us who do.