Masz projekt A, który się buduje do exe. Masz projekt B, który w pewnym sensie rozszerza to exe.
Teraz musisz się zastanowić, w jaki sposób chcesz zbudować projekt B. Czy po prostu jako statycznego liba, czy dll z eksportowanymi klasami, czy klasyczną dll.
Statyczny lib - to już ponoć wiesz.
DLL z eksportowanymi klasami - klasy, które mogą być wykorzystywane w pliku exe, muszą być wyeksportowane. Czyli podczas budowania projektu B te klasy muszą być oznaczone jako eksportowane, a w projekcie A jako importowane. Robi się to za pomocą odpowiedniego makra (w uproszczeniu):
Plik h:
Kopiuj
#ifdef PROJECTB_EXPORTS
#define PROJECTB_API __declspec(dllexport)
#else
#define PROJECTB_API __declspec(dllimport)
#endif
class PROJECTB_API MojaKlasa
{
}
Następnie w projekcie B dodajesz w ustawieniach projektu dyrektywę PROJECTB_EXPORTS (Visual zazwyczaj doda Ci coś takiego automatycznie, jeśli tworzysz dll).
Dzięki temu projekt B będzie wiedział, że klasę ma eksportować, a projekt A (gdzie includujesz ten plik h) będzie wiedział, że klasę ma importować (bo nie ma nigdzie dyrektywy PROJECTB_EXPORTS).
A potem w projekcie A możesz się posługiwać taką dllką, jakby była zwykłą statyczną biblioteką:
Kopiuj
MojaKlasa obj = new MojaKlasa();
Ta metoda ma swoje plusy i minusy. Plusy są takie, że masz dll, którego możesz używać jak liba.
Minusy:
- nie możesz w klasie jawnie posługiwać się standardową biblioteką. Tzn. nie możesz zrobić czegoś takiego:
Kopiuj
class PROJECTB_API MojaKlasa
{
void print(const std::wstring & msg);
}
Musisz np.:
Kopiuj
class PROJECTB_API MojaKlasa
{
void print(const wchar_t * pMsg);
}
Lub jakaś własna obsługa stringa. Nie możesz w taki sposób przekazywać, ponieważ wersje biblioteki standardowej różnią się i dla każdego kompilatora są nieco inne binarnie. Oznacza to, że jeśli projekt B zbudujesz w jednym kompilatorze (np. VisualStudio 2012) i będziesz chciał go używać z poziomu projektu utworzonego w innym kompilatorze (np. VisualStudio 2013), to pojawią się błędy w działaniu związane z pamięcią. W ogóle taki kod chyba nawet nie skompiluje się poprawnie. Tzn. jeśli klasa jest eksportowana, to wszystkie jej składniki też muszą być oznaczone jako eksportowane. Obiekty biblioteki standardowej takie nie są.
Nie wiem też, czy można taką dllkę zastosować bez problemów w innym języku, niech się ktoś wypowie.
Masz jeszcze trzecią możliwość. Klasyczna dllka.
W pliku h umieszczasz deklarację jakiegoś interfejsu.
Umieszczasz też funkcję, która utworzy Ci obiekt tego interfejsu i kolejną, która go zniszczy. W skrócie to mogłoby wyglądać tak:
Kopiuj
class IPrintable
{
public:
virtual void PrintMsg(const wchar_t * pMsg) = 0;
virtual void PrintError(const wchar_t * pMsg) = 0;
};
extern "C" bool __stdcall CreateObject(IPrintable *& pObj);
extern "C" void __stdcall DestroyObject(IPrintable *& pObj);
}
Gdzieś w jakimś pliku cpp w projekcie B deklarujesz klasę, która dziedziczy po IPrintable i te funkcje.
Potem w execu jest już trochę trudniej. Musisz załadować taką bibliotekę (LoadLibrary), a następnie odnaleźć określone funkcje (GetProcAddress), itd. Odsyłam tu do netu, bo i tak się dość mocno rozpisałem :) Pamiętaj jednak, że poza takimi deklaracjami, powinieneś zrobić odpowiednie wpisy w pliku def, bo c++ Ci i tak zmieni nazwy funkcji mimo jawnie zastosowanej konwencji (__stdcall).
Generalnie w żadnym z wypadków nie powinieneś eksportować żadnej funkcji, która w argumencie przyjmuje typ z biblioteki standardowej. O tym już pisałem. W ostatnim przypadku pokazałem Ci też, że to projekt B musi zatroszczyć się o stworzenie i zniszczenie eksportowanego obiektu. Z tego samego powodu. Alokacja i dealokacja pamięci różnią się binarnie pomiędzy różnymi kompilatorami.
Teraz jeśli jeden projekt (A) korzysta w jakiś sposób z drugiego (B), to projekt A powinien być zależny od B (dependency), co spowoduje, że projekt B zbuduje się zanim zacznie budować się projekt A. I będziesz też musiał dodać do inputa w projekcie A liba utworzonego na podstawie projektu B(chyba, że projekt B to klasyczna dllka, wtedy linker Cię nie interesuje).
Mam nadzieję, że nie zamotałem za bardzo i wiesz o co chodzi.