Gaminu čia mokslams tokį kursinį. Semestro darbas. Nors pradžioje turėjom vilčių pradėt (ir užbaigt) kuo anksčiau, bet va, mokslų liko tik viena savaitė, o mūsų projektas dar neužbaigtas. Norėjosi geriau, gavosi kaip visada. Žodžiu, reikia parašyti programą, dirbančią su aprašytomis schemomis. Nusprendžiau, kad bus labai gražu ir patogu duotas schemas sukompiliuoti į DLL failus, o paskui, programos vykdymo eigoje, vartotojas (aka dėstytojas) galės pasirinkti schemą. Vakar teko užtektinai su tuo pasikrušti. Pagal visus oficialius ir neoficialius pavyzdžius NIEKAIP nepavyko suprograminti, kad DLL’as būtų užkraunamas dinamiškai.
Anot visokių wikipedijų ir MSDN’ų, apsirašom DLL’ą maždaug taip:
#include <windows .h>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}
//Eksportuojam funkciją.
extern "C" __declspec(dllexport) int test()
{
return 123;
}
Sukompiliuosim ir turėsim DLL’ą su labai reikalinga funkcija test(), kuri grąžins 123 :-) Dabar galim bandyti naudoti šį kūrinį statiškai (bandžiau įsitikinti ar veikia).
#include <windows .h>
#include <iostream>
//Importuojam funkciją.
extern "C" __declspec(dllimport)int test();
int main(int argc, char **argv)
{
int tmp = test();
std::cout < < tmp << endl;
return 0;
}
Viskas kaip ir OK, veikė kuo puikiausiai (į projektą įtraukus *.lib). Reiškia DLL’as gyvas. Bet kadangi mano užduočiai statinis variantas netiko, nes schemų gali būti bet kokių ir bet kiek, tai reikėjo rinktis dinaminį DLL užkrovimą. Maždaug pasirenku kokį noriu failą, jis patikrinamas ar tai būtent schemos failas (ar turi reikiamus metodus), jei viskas tvarkoj - naudojam. Viso šito sourcas toks:
#include <windows .h>
#include <iostream>
//Būsimos funkcijos aprašas.
typedef int (*importFunction)();
int main(int argc, char **argv)
{
importFunction test;
int result;
//Užkraunam DLL'ą.
HINSTANCE hinstLib = LoadLibrary("ManoDLL.dll");
if (hinstLib == NULL)
{
std::cout < < "ERROR: unable to load DLL" << endl;
return 1;
}
// Gaunam rodyklę į funkciją.
test = (importFunction)GetProcAddress(hinstLib, "test");
//Tikrinam ar funkcija egzistuoja.
if (test == NULL)
{
std::cout << "ERROR: unable to find DLL function" << endl;
FreeLibrary(hinstLib);
return 1;
}
result = test();
// Iškraunam DLL'ą iš atminties.
FreeLibrary(hinstLib);
std::cout << "The result was: " << result << endl;
return 0;
}
Va čia ir prasidėjo bėdos. DLL’as būdavo užkraunamas, tačiau GetProcAddress vis nesugebėdavo atrinkti reikiamo metodo. Kas man iš to dll’o jei negaliu naudot jo metodų? Buvo siūlymų prie metodo eksportinimo darašyt cdecl, tačiau tai nepadėjo. Po kelių valandų bandymų ir ieškojimų išradau, jog DLL’e aprašant funkciją, reik prirašyt __stdcall:
//Eksportuojam funkciją.
extern "C" __declspec(dllexport) int __stdcall test()
{
return 123;
}
Dabar viskas veikia kuo puikiausiai :-) Daugiau info MSDN’e ir Wikipedijoj.
Pagaliau sulaukiau Tavo įrašo, kuris manęs visai nesudomino :D
Priimu tai kaip komplimentą, kad visi prieš tai buvę įrašai tau buvo įdomūs :-)