"Gonex" <nospam@please.tk> wrote in message
news:9emeqm$sb$1@news.inet.tele.dk...
>
> [klip]
> > En anden måde, er at lægge sig op af Microsoft COM-modellen:
> > Definer et abstrakt interface.
> > Implementer en konkret implementation af det abstrakte interface i DLL.
> > Lav en factory funktion, som benyttes til at oprette objekter af den
> > konkrete type.
> > Så slipper du for at eksportere klassen i det hele taget!
> [klip]
>
> Jeg er i gang med at lære COM (Skal faktisk til eksamen i et valgfag der
> hedder C++, COM, DCOM & COM+), og kunne sikkert godt løse problemet den
vej.
> Meningen var dog at jeg gerne ville have noget af den grundlæggende dll
> viden lidt på plads. Desuden har jeg haft opfattelsen af at COM er
overkill
> til "småting".
COM løser nogle opgaver og har sit eget sæt af problemer (skrøbelig
installation, versionering, begrænset typesystem etc.). Ingenting er gratis.
Se argumentationen for .NET.
Min udlægning er at COM er godt/brugbart når man skal:
* Krydse programmerings sprog grænser (især når Visual Basic skal bruge )
* Krydse process grænser (incl. netværks grænser)
* Interface til systemer, som kræver COM - f.eks. MTS.
Hvis man ikke har nogen af ovenstående problemer, bidrager COM kun med
ekstra kompleksitet.
Man kan sagtens lære en del af COM's interface baserede design - men det
betyder ikke at man _skal_ bruge COM for at lave tilsvarende eller bedre
implementeringer.
Jeg foreslog _ikke_ at du skulle bruge COM.
Jeg foreslog bl.a. at man kan lave:
* Et abstrakt interface
* En konkret implementering af det konkrete interface
* En factory funktion til at oprette og nedlægge objekter
Den model _svarer_ fuldstændigt til hvad COM gør, men har ikke begrænsninger
og krav med hensyn til registry, fejlrapportering, begrænset typesystem etc.
Hvis du har et interface kaldet "test_class", som bliver implementeret i den
konkrete klasse "test_class_impl", og du gerne vil have "test_class_impl"
til at ligge i et DLL kaldet MY_DLL.DLL, så har du følgende:
----------------- start på TEST_CLASS.H ----------------------------
#ifndef TEST_CLASS_H_GUARD
#define TEST_CLASS_H_GUARD
#include <vector>
class test_class
{
public:
test_class(void);
virtual ~test_class();
class some_error {};
virtual bool some_func(std::vector<int>& vi) throw (some_error) = 0;
private:
test_class(const test_class&);
test_class& operator=(const test_class&);
};
#endif
------------ start på TEST_CLASS.CPP -------------------------------
#include "test_class.h"
test_class::test_class(void)
{
}
test_class:
test_class()
{
}
-------------- start på TEST_IMPL.H --------------------------
#ifndef TEST_IMPL_H_GUARD
#define TEST_IMPL_H_GUARD
#include "test_class.h"
class test_class_impl : public test_class
{
public:
test_class_impl(void);
virtual bool some_func(std::vector<int>& vi) throw (some_error);
private:
test_class_impl(const test_class_impl&);
test_class_impl& operator=(const test_class_impl&);
};
#endif
--------------- start på TEST_IMPL.CPP ---------------------------
#include "test_impl.h"
test_class_impl::test_class_impl(void) :
test_class()
{
}
bool test_class_impl::some_func(std::vector<int>& vi) throw
(test_class::some_error)
{
if(vi.empty()) {
throw test_class::some_error();
}
return true;
}
--------------------- start på MY_DLL.H ---------------------------------
#ifndef MY_DLL_H_GUARD
#define MY_DLL_H_GUARD
#include "test_class.h"
test_class& __declspec(dllimport) create_test_class(void);
void __declspec(dllimport) destroy_test_class(test_class& to);
#endif
----------------------- start på MY_DLL.CPP --------------------------
#include <windows.h>
#include "test_impl.h"
int WINAPI DllEntryPoint(HINSTANCE /*hinst*/, unsigned long /*reason*/,
void* /*lpReserved*/)
{
return 1;
}
test_class& __declspec(dllexport) create_test_class(void)
{
return *new test_class_impl;
}
void __declspec(dllexport) destroy_test_class(test_class& to)
{
delete &to;
}
DLL'et MY_DLL.DLL består af følgende source filer:
MY_DLL.CPP
TEST_CLASS.CPP
TEST_IMPL.CPP
bemærk at de vigtige klasser "test_class" og "test_class_impl" er
fuldstændig almindelig, platform neutral ANSI C++.
Der er _ikke_ gjort noget for at eksportere klasserne - det er ikke
nødvendigt!
Kun MY_DLL indeholder noget kode der har med Windows og DLL'er at gøre.
DLL'er (og COM) er _ikke_ et design-fænomen, men en deployment teknologi!
Jeg mener at man gør sig selv en bjørnetjeneste ved at tro noget andet -
selvom det ikke er usædvanligt.
Man kun nu bruge det i et program, som f.eks.:
#include "my_dll.h"
int main(void)
{
test_class* to = 0;
try {
to = &create_test_class();
to->some_func(std::vector<int>());
destroy_test_class(*to);
return 0;
}
catch(...) {
if(to) {
destroy_test_class(*to);
}
return 1;
}
}
som dog inkluderer den DLL-specifikke fil. Det kan man dog også sagtens
skjule - hvis man har brug for det.
Enhver nogenlunde Windows compatibel C++ compiler bør kunne klare
ovenstående.
>
> [klip]
> > Hvis du bruger dynamisk linkning, er det nemmere at anvende import
library
> i
> > stedet for LoadLibrary.
> [klip]
>
> Det kan godt vøre jeg spørger dumt nu, men mener du #import af et
> typebibliotek *.tlb eller selve dll'en, altså i stil med #include, eller
er
> det en funktion/procedure, eller noget helt andet?
Når du laver et DLL, hvorfra der bliver eksporteret nogle funktioner, laver
linkeren et import library, som er en LIB-fil der hedder det samme som DLL.
Hvis du includerer headerfilerne der erklærer de eksporterede funktioner, og
linker import librariet med, så skal man ikke gøre yderligere.
Personligt bryder jeg mig ikke om #import.
Det er YARLE (yet another redundant language extension), som jeg ikke mener
tjener andet formål end at sovse koden ind i Microsoft platformsbindinger,
uden at give noget til nævneværdigt til gengæld.
>
> Konklusionen må være at det (næsten) ikke er muligt at eksportere en
klasse
> ud af en dll, kun funktioner/procedure.
Nej, overhovedet ikke. Kig f.eks. på MFC DLL'et. Der er masser af DLL'er der
eksporter klasser. Hvis det er konkrete klasser, de eksporterer, må de bruge
import libraries - så vidt jeg kan se.
Virkede det du havde skrevet i dit oprindelige indlæg ikke ? Det så ud til
at være tæt på.
Eller start din compiler op, klik på nogle passende Wizards hurtigt efter
hinanden - så skulle den være hjemme.
Venlig hilsen
Mogens Hansen