Borland C++ Builder Enterprise biblioteka DLL

0

Mam zamiar uczyć się tworzenia bibliotek DLL oraz aplikacji, które będą je wykorzystywać - mój pierwszy program który do tego stworzyłem ma za zadanie ładować bibliotekę po wciśnięciu guzika "dodaj" przenieść wartości zmiennych do tej biblioteki, w DLL-ce obliczyć wartość tych 2-óch zmiennych i z powrotem wysłać do aplikacji wartość wyniku - niestety - tak się nie dzieję - nie umiem jeszcze bawić się tak złożonymi programami, a te wszystkie kursy, informacje, które znalazłem na Google nie pomogły mi rozwiązać problemu. Jaka jest przyczyna, że program nie działa ?

Kod aplikacji :

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

#include <vcl.h>
#pragma hdrstop
#pragma argsused
#include "Unit1.h"
int wynik;
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
extern "C" __declspec(dllimport)void dzialanie(int a, int b, int w){

 };
//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ExitClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::DodajClick(TObject *Sender)
{
int l1, l2;
l1=L1->Text.ToInt();
l2=L2->Text.ToInt();

dzialanie(l1, l2, wynik);
 W->Text=wynik;
}
//---------------------------------------------------------------------------

Kod biblioteki:

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

#include <vcl.h>
#include <windows.h>
#pragma hdrstop
#pragma argsused
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) void dzialanie( int a, int b, int w);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
        return 1;
}
//---------------------------------------------------------------------------
void dzialanie (int a, int b, int wynik)
  {
   wynik = a+b;
  }

Jeśli istnieje taka potrzeba, zawsze moge komuś wysłać cały projekt, do pomocy.

0

Jaka jest przyczyna, że program nie działa ?

Nie jest to wynik jego wielkiej złożoności i użycia .dll , bez .dll też by nie działało .
Odpowiedz sobie na pytanie w jaki sposób zwrócić wartość z funkcji ?, jest kilka sposobów
a ty nie użyłeś żadnego poprawnego .

extern "C" __declspec(dllexport) int dzialanie( int a, int b);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
        return 1;
}
//---------------------------------------------------------------------------
int dzialanie (int a, int b)
  {
    return a+b;
  }
int l1, l2;
l1=L1->Text.ToInt();
l2=L2->Text.ToInt();

wynik = dzialanie(l1, l2);
0

A czy mógłbym wykorzystać tutaj procedurę? Bo tak miałem zamiar zrobić, aby nie korzystać z funkcji. Dziękuję - sprawdzę jak to będzie działać.

Teraz wynik jest zwracany, ale wartośc jest kosmiczna ;( Czy w tym miejscu:

//---------------------------------------------------------------------------
extern "C" __declspec(dllimport)int dzialanie(int a, int b){

 };
//---------------------------------------------------------------------------

Nie powinno zwracać jakiejś wartości zmiennych? Próbowałem wpisać tam return wynik, return dzialanie i nie działa, hmm czegoś tu jeszcze brakuje ;/

0

Dzizus,,, nie , to tylko deklaracja , kod masz mieć w .dll .ma być tak :
W .EXE

extern "C" __declspec(dllimport)int dzialanie(int a, int b);

W DLL :

extern "C" __declspec(dllexport) int dzialanie( int a, int b);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
        return 1;
}
//---------------------------------------------------------------------------
int dzialanie (int a, int b)
  {
    return a+b;
  }
0

Jeśli w exe w miejscu :

extern "C" __declspec(dllimport)int dzialanie(int a, int b);

nie wstawię {} to wywala mi błąd linkera. Teraz wartość wyniku jest zwracana, ale jest to liczba 1242560 nie ważne jakie liczby do siebie dodam. Jeszcze jest ostrzeżenie że właśnie w tym miejscu funkcja powinna zwracać jakąś wartość.

0

Nie wstawiaj {} , dobrze ze zgłasza błąd , musisz dodac jeszcze plik .lib z projektu biblioteki .dll
i wrzucić .dll do katalogu aplikacji lub systemowego .

http://cyfbar.republika.pl/dll.htm

http://cyfbar.republika.pl

0

Ten kurs jest chyba do jakiś innych środowisk, ja używałem tego kursu : http://www.functionx.com/bcb/libraries/staticdll.htm
Zresztą u mnie Generate import library jest na szaro i nie można ją zaznaczyć ani odznaczyć.

0

Plik dll jest w katalogu z aplikacją tak samo jak plik lib, tylko, że tutaj linker wywołuje taki błąd:
[Linker Error] Unresolved external '_dzialanie' referenced from D:\SZKOŁA\PROGRAMOWANIE\C\WIN32\BIBLIOTEKI\UNIT1.OBJ

A jak wstawię {} to działa, jeśli będę mógł wstawiać tylko statycznie biblioteki poprzez wpisywanie ich nazw, np. w taki sposób:
HANDLE DLLHandle = LoadLibrary("Library_name.dll");
To będzie trochę odbiegało od moich planów- gdyż myślałem nad zrobieniem sobie programu, który korzysta z różnych bibliotek nie zmieniając kodu aplikacji.

0

A , o to chodzi .
Przy tworzeniu biblioteki [ trzeba przekompilować jeszcze raz] daj :
Projekt ->Options.. .
Na karcie Advanced Compiler usuń zaznaczenie Generate Uderscores .
To powinno utworzyć bibliotekę z której funkcje będą dostępne pod oryginalnymi nazwami .
Z zaznaczaną opcją do nazw eksportowanych funkcji dodawany jezt znak _ -> _nazwafun .

0

Niestety to nie pomogło - dalej zwraca tą samą liczbę: 1242560
Zresztą wtedy wywala jeszcze więcej błędów.

0

E tam u mnie działa i ma być zaznaczone Generate Underscores.
Robimy Bibliotekę :
opcje tworzenia - Zakładki Project ->Options ... , :

Linker -> Zaznaczyć Generate import library .

Linker -> Usunąć zaznaczenie Use dynamic RTL

Packages ->Usunąć zaznaczenie Build with runtime packages

Advanced Compiler -> Pozostawić zaznaczone Generate Underscores

Compiler -> włączyć Release

Po kompilacji otrzymamy pliki nazwa.lib i nazwa.dll .

Kod dll :

//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) int __fastcall dzialanie( int a, int b);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
    return 1;
}
//---------------------------------------------------------------------------
int __fastcall dzialanie (int a, int b)
  {
    return a+b;
  }

//--------------------------------------------------------------------
Robimy Aplikację :
Normalnie , nowy formularz i td ..
[Advanced Compiler -> Pozostawić zaznaczone Generate Underscores]
Zapisujemy projekt .
Do katalogu w którym zapisaliśmy projekt , przenosimy .lib i .dll lub zapisujemy projekt Aplikacji
w tym samym katalogu co projekt .dll .

Do projektu Aplikacji dodajemy poprzez opcję Projekt -> Add to project...
plik nazwa.lib.

Kompilujemy .

Kod Aplikacji Form1 + Button1 :

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
extern "C" __declspec(dllimport) int __fastcall dzialanie( int a, int b);
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
     int wynik = dzialanie(2,2) ;
     ShowMessage( wynik ) ;
}
//---------------------------------------------------------------------------

Niech Kostucha zrobi według opisu , jak to nie zadziała to się poddaję ...
Pozdro.

0

A więc tak - wynik wyniósł 4 więc tak ma być :)
Nie wiem czemu, ale mi nie działało w moim starym projekcie :( Może za dużo już tam namieszałem :( Ale na nowym już tak :) Bardzo dziękuję.
I teraz za każdym razem muszę tak robić jak chcę tworzyć jakąś bibliotekę ?
Załózmy że mam już ten program - może on wyświetlać wszystkie pliki dll które w odpowiedniej funkcji wysłały np. text - "jestem twoja biblioteka" - załóżmy - bez zmiany kodu tej aplikacji?
Pytam się bo zastanawiam się, jak np. twórcy komunikatorów umożliwiają innym osobą tworzyć takie biblioteki któe działają w tym komunikatorze - bez zmiany aplikacji (kodu tego komunikatora) i ja właśnie coś takiego chcę się nauczyć - stworzyć taką prostą aplikację, która np. wyświetla różne biblioteki i współpracuje z nimi - więc chyba nie mogę za każdym razem dodawać do projektu plik z rozszerzeniem .lib i kompilować go bo nie bardzo na tym mi zależy.
Ale dziękuję - pierwsza aplikacja korzystająca z DLL działa :)

0

No więc ta metoda dołączania bibliotek wymaga dodania do projektu kompilowanego
pliku .lib .
W czasie uruchamiania programu biblioteka .dll jest ładowana tak jak inne systemowe
niezbędne do działania programu . Bez tej biblioteki program się nie uruchomi .

Inną metodą jest ładowanie dynamiczne w czasie wykonania programu , przez LoadLibrary .
Tutaj program może załadować bibliotekę w dowolnym momencie przed użyciem jak i
usunąć .
Umożliwia to podstawianie różnych bibliotek , oczywiście z zachowniem eksportowanych
symboli i nie wymaga statycznego linkowania z plikiem .lib .
To rozwiązanie było by odpowiednie do twoich celów .
[ uwaga . Jeśli dynamicznie ładujesz bibliotekę utworzoną w Builder przez LoadLibrary ,
a następnie uzyskujesz adres funkcji poprzez GetProcAddress to funkcja zawarta w bibliotece
będzie miała nazwę z '_' , [chyba że usuniesz Generate Underscores]
czyli GetProcAddress(Hndle_dll,"_nazwaFun") .]

A wtyczki to już raczej klasy i ich interface udostępniane przez bibliotekę .
na pewno znajdziesz coś na google odnośnie wtyczek jak i dynamicznego ładowania .dll ....

0

Aha rozumiem - muszę zapoznać się z funkcją LoadLibrary, a co za tym idzie jej pochodne - między innymi GetProcAddress i Handle (czy jakoś tak). Trzeba się brać do roboty :)
A przy tworzeniu dllki to wszystko tak samo jak było wcześniej - czyli powyłączać te opcje w projekcie? Tak samo zmienić opcje w projekcie aplikacji i dodatkowo wyłączyć generate underscores tak?

I tak niedługo się zgłoszę po rady bo czarno to widzę :)

0

na razie to wyłącz tylko przy .dll Projekt -> Options .. Packages ->Build with runtime packages i
Linker ->Use Dynamic RTL
To może sprawiać problemy przy uruchamianiu biblioteki.
Reszta w zasadzie powinna zostać bez zmian przy pisaniu i testowaniu .
W wersji końcowej powinno sie dać jedynie Compiler -> Release .
powodzenia .

Co do generate underscores , jak będzie zaznaczone to nazwy funkcji będą widoczne
ze znakiem '_' . Czyli jeśli będziesz chciał załadować dynamicznie funkcję która w bibliotece nazywa się np. MojaFun poprzez GetProcAddress to w wywołaniu GetProcAddress musisz użyć nazwy _MojaFun.

0

Szukałem w google na temat tych wtyczek i zauważyłem, że przy wpisywaniu LoadLibrary zawsze wpisują nazwę tej biblioteki, a jeśli ja nie znam nazwy tej biblioteki, którą chcę załadować to czy mogę wpisać LoadLibrary("*.dll") tak aby mi załadował wszystkie istniejące w danym katalogu biblioteki? zakładając, że po zbudowaniu apliakcji - nie będe zmieniał jej kodu, tylko dopisywał same wtyczki.

0

nie mozesz. LoadLibrary musisz wywolac explicite dla kazdej jednej biblioteki ktora chcesz dynamicznie dopiac. tak wiec, po prostu, czeka Cie albo czytanie pliku konfiguracyjnego gdzie sobie zapiszesz kolejno wsyzstkie moduly do zaladowania, albo przegladanie katalogu w poszukiwaniu dll'ek

0

A jak mogę zrobić aby wyszukać wszystkie biblioteki w danym katalogu, pobrać ich nazwy, a następnie załadować którąkolwiek z nich ?

I następne pytanie. Zrobiłem przykład z tej strony: http://www.programuj.com/artykuly/bcb/dllki.php

Program działa, tylko nie wiem gdzie mogę wpisać polecenie FreeLibrary - próbowałem w projekcje aplikacji - tam gdzie w zdarzeniach formy jest OnClose() wpisywałem to polecenie, ale wyskakiwał mi błąd programu przy zamykaniu, to polecenie wpisywałem także przez zamknięciem tej metody przycisku po wywołaniu wszystkich czynności, a także w samej bibliotece i za każdym razem, przy wyłączaniu programu występował błąd. Przepisałem jeszcze raz ten program na nowo i dalej to samo, tylko że już błąd zgłasza explorer (to okienko przepraszamy aplikacja taka i taka spowodowała błąd... to okienko z przyciskami debuguj i zamknij) i nie wiem jak pozbyć się mam tego problemu ;/

Zastanawia mnie fakt - czy przy ładowaniu dynamicznie takiej biblioteki nie musże wpisywać __specdecl(dllimport) ? Tak jak jest w tym przykładzie:

typedef void __stdcall (*PROCRunThisModule)();
extern "C" void __stdcall RunThisModule();

Oraz definiować ten typ ze wskaźnikiem także za każdym razem, do każdej funckji muszę tak robić? Mam wrażenie, że jak wcześniej przeglądałem różne kursy, akurat tego nie było ... Hmm.

0

Nie mogę sobie poradzić z tym kodem ;/

TSearchRec plik;

 FindFirst("*.dll",faAnyFile,plik);
  ListBox1->Items->Add(plik.Name);
  while (FindNext(plik) == 0);
   ListBox1->Items->Add(plik.Name);
 FindClose(plik);

Jak zrobić, aby nie wpisywał dwa razy tego samego pliku (tak się dzieje, gdy jest tylko jedna biblioteka) i uciąć rozszerzenie ?

Ok. Problem rozwiązany :P Tylko zastanawiam się jeszcze nad ucięciem rozszerzenia przy wpisywaniu nazwy w listboxie

0

Usunąć
while (FindNext(plik) == 0); <- ten średnik i stosować {} ?
// edit
ojć , nie ta fun..

ucięciem rozszerzenia

String FileName = "xx.dll" ;
       FileName[FileName.AnsiPos(".dll")]='\0';
0

Chciałem teraz przeszukać cały katalog w poszukiwaniu plików dll, następnie załadować ją i wyszukać procedury Wiadomość(String nawa). Jeśli znajdzie taką procedurę w tym pliku dll to powinien z niej pobrać łańcuch i wpisać go do listboxa. Wzorując się na podanych wcześniej rozwiązaniach - nie udaje mi się [???] [glowa]

Kod biblioteki:

//---------------------------------------------------------------------------
#include <vcl.h>
#include <windows.h>
#pragma hdrstop
//---------------------------------------------------------------------------
extern "C" __declspec (dllimport) void Wiadomosc( String nazwa);

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
        return 1;
}
//---------------------------------------------------------------------------

void Wiadomosc (String nazwa){
 nazwa = "DelOne";            }

Kod aplikacji:

typedef void __stdcall (*pcWiadomosc)(String nazwa);
extern "C" void __stdcall Wiadomosc(String nazwa);

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

TSearchRec plik;
  FindFirst ("*.dll",faAnyFile,plik);
     HINSTANCE PlikDll = LoadLibrary ("plik.Name");
      pcWiadomosc(String nazwa) _Wiadomosc(String nazwa) = (pcWiadomosc(String nazwa) GetProcAddress(PlikDll,"Wiadomosc(nazwa)");
       ListBox1->Items->Add(nazwa);
  FindClose(plik);

Jak na razie to mam kłopot przy aplikacji ;/ ;-(

0

PANOWIE ...

No a co w takim przypadku :

żeby nasza aplikacja działała na komputerze gdzie nie ma buildera to wystarczyło zazwycaj odznaczyć
Build with runtime packages i use dynamic RTL ... prawda .. ?

no ale jak mam dołączoną swoją najprostszą w świecie dllke statycznie i w programie moim jest użyta choć raz jakaś funkcja dllki to program nie działa na innych komputerach bez buildera a wyłączanie packages i rtl nie pomaga.

Natomiast jeżeli biblioteka dll jest podpieta ale nie używam ani jednej funkcji ze środka to program po kompilacji sie odpala bez problemu na innych komputerach.

Majstrowałem z RTL i Packages podczas kompilacji biblioteki ale nic nie pomogło...

wiec ?? co jest nie tak ?

0

Witam chciałbym odświerzyć temat ;) w związku z tym mam pytanie ;) jak z gotowych plików np. z http://sourceforge.net/project/showfiles.php?group_id=979 zrobić bibliotekę działającą pod borland C++

bo ja nie wiem jak :-P

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