Importowanie wywołań funkcji przy użyciu polecenia __declspec(dllimport)
Dodawanie adnotacji do wywołań za pomocą elementu __declspec(dllimport)
może przyspieszyć ich działanie. __declspec(dllimport)
jest zawsze wymagany do uzyskania dostępu do wyeksportowanych danych DLL.
Importowanie funkcji z biblioteki DLL
Poniższy przykład kodu przedstawia sposób importowania __declspec(dllimport)
wywołań funkcji z biblioteki DLL do aplikacji. Załóżmy, że func1
jest to funkcja, która znajduje się w bibliotece DLL niezależnie od pliku wykonywalnego zawierającego funkcję main .
Bez __declspec(dllimport)
polecenia podanego w tym kodzie:
int main(void)
{
func1();
}
kompilator generuje kod, który wygląda następująco:
call func1
a konsolidator tłumaczy wywołanie na coś takiego:
call 0x4000000 ; The address of 'func1'.
Jeśli func1
istnieje w innej biblioteki DLL, konsolidator nie może rozpoznać tego adresu bezpośrednio, ponieważ nie ma możliwości poznania, jaki jest adres func1
. W środowiskach 32-bitowych i 64-bitowych konsolidator generuje thunk pod znanym adresem. W środowisku 32-bitowym thunk wygląda następująco:
0x40000000: jmp DWORD PTR __imp_func1
Oto __imp_func1
adres func1
miejsca w tabeli adresów importu pliku wykonywalnego. Wszystkie te adresy są znane konsolidatorowi. Moduł ładujący musi zaktualizować tylko tabelę adresów importu pliku wykonywalnego w czasie ładowania, aby wszystko działało poprawnie.
Dlatego użycie __declspec(dllimport)
jest lepsze: ponieważ konsolidator nie generuje thunk, jeśli nie jest wymagany. Thunks sprawiają, że kod jest większy (w systemach RISC, może to być kilka instrukcji) i może obniżyć wydajność pamięci podręcznej. Jeśli informujesz kompilator, że funkcja znajduje się w bibliotece DLL, może wygenerować wywołanie pośrednie.
Teraz ten kod:
__declspec(dllimport) void func1(void);
int main(void)
{
func1();
}
generuje następującą instrukcję:
call DWORD PTR __imp_func1
Nie ma tunk i nie ma jmp
instrukcji, więc kod jest mniejszy i szybszy. Możesz również uzyskać ten sam efekt bez __declspec(dllimport)
użycia całej optymalizacji programu. Aby uzyskać więcej informacji, zobacz /GL (Optymalizacja całego programu).
W przypadku wywołań funkcji w bibliotece DLL nie chcesz używać wywołania pośredniego. Konsolidator zna już adres funkcji. Ładowanie i przechowywanie adresu funkcji przed wywołaniem pośrednim zajmuje trochę czasu i miejsca. Bezpośrednie wywołanie jest zawsze szybsze i mniejsze. Chcesz użyć __declspec(dllimport)
tylko podczas wywoływania funkcji DLL spoza samej biblioteki DLL. Nie używaj __declspec(dllimport)
funkcji wewnątrz biblioteki DLL podczas kompilowania tej biblioteki DLL.