Bagikan melalui


Impor Timah

Mengekspor atau mengimpor ke file lain yang dapat dieksekusi menunjukkan komplikasi ketika impor saling menguntungkan (atau melingkar). Misalnya, dua DLL mengimpor simbol satu sama lain, mirip dengan fungsi yang saling rekursif.

Masalah dengan saling mengimpor file yang dapat dieksekusi (biasanya DLL) adalah bahwa tidak dapat dibangun tanpa membangun yang lain terlebih dahulu. Setiap proses build memerlukan, sebagai input, pustaka impor yang dihasilkan oleh proses build lainnya.

Solusinya adalah menggunakan utilitas LIB dengan opsi /DEF, yang menghasilkan pustaka impor tanpa membangun file yang dapat dieksekusi. Dengan menggunakan utilitas ini, Anda dapat membangun semua pustaka impor yang Anda butuhkan, tidak peduli berapa banyak DLL yang terlibat atau seberapa rumit dependensinya.

Solusi umum untuk menangani impor bersama adalah:

  1. Ambil setiap DLL secara bergantian. (Pesanan apa pun layak, meskipun beberapa pesanan lebih optimal.) Jika semua pustaka impor yang diperlukan ada dan saat ini, jalankan LINK untuk membangun file yang dapat dieksekusi (DLL). Ini menghasilkan pustaka impor. Jika tidak, jalankan LIB untuk menghasilkan pustaka impor.

    Menjalankan LIB dengan opsi /DEF menghasilkan file tambahan dengan . Ekstensi EXP. Si. File EXP harus digunakan nanti untuk membangun file yang dapat dieksekusi.

  2. Setelah menggunakan LINK atau LIB untuk membangun semua pustaka impor, kembali dan jalankan LINK untuk membangun file yang dapat dieksekusi yang tidak dibangun pada langkah sebelumnya. Perhatikan bahwa file .exp yang sesuai harus ditentukan pada baris LINK.

    Jika Anda telah menjalankan utilitas LIB sebelumnya untuk menghasilkan pustaka impor untuk DLL1, LIB juga akan menghasilkan file DLL1.exp. Anda harus menggunakan DLL1.exp sebagai input ke LINK saat membangun DLL1.dlll.

Ilustrasi berikut menunjukkan solusi untuk dua DLL yang saling mengimpor, DLL1 dan DLL2. Langkah 1 adalah menjalankan LIB, dengan opsi /DEF diatur, pada DLL1. Langkah 1 menghasilkan DLL1.lib, pustaka impor, dan DLL1.exp. Pada langkah 2, pustaka impor digunakan untuk membangun DLL2, yang pada gilirannya menghasilkan pustaka impor untuk simbol DLL2. Langkah 3 membangun DLL1, dengan menggunakan DLL1.exp dan DLL2.lib sebagai input. Perhatikan bahwa file .exp untuk DLL2 tidak diperlukan karena LIB tidak digunakan untuk membangun pustaka impor DLL2.

Diagram yang memperlihatkan input dan output saat Anda menggunakan impor bersama untuk menautkan dua DLL.
Menautkan Dua DLL dengan Impor Bersama

Batasan _AFXEXT

Anda dapat menggunakan _AFXEXT simbol preproscessor untuk DLL ekstensi MFC Anda selama Anda tidak memiliki beberapa lapisan DLL ekstensi MFC. Jika Anda memiliki DLL ekstensi MFC yang memanggil atau berasal dari kelas di DLL ekstensi MFC Anda sendiri, yang kemudian berasal dari kelas MFC, Anda harus menggunakan simbol praprosesor Anda sendiri untuk menghindari ambiguitas.

Masalahnya adalah bahwa di Win32, Anda harus secara eksplisit menyatakan data apa pun seolah-olah __declspec(dllexport) akan diekspor dari DLL, dan __declspec(dllimport) jika akan diimpor dari DLL. Saat Anda menentukan _AFXEXT, header MFC memastikan bahwa AFX_EXT_CLASS ditentukan dengan benar.

Ketika Anda memiliki beberapa lapisan, satu simbol seperti AFX_EXT_CLASS tidak cukup, karena DLL ekstensi MFC mungkin mengekspor kelas baru serta mengimpor kelas lain dari DLL ekstensi MFC lainnya. Untuk mengatasi masalah ini, gunakan simbol praprosesor khusus yang menunjukkan bahwa Anda membangun DLL itu sendiri versus menggunakan DLL. Misalnya, bayangkan dua DLL ekstensi MFC, A.dll dan B.dll. Mereka masing-masing mengekspor beberapa kelas di A.h dan B.h. B.dll menggunakan kelas dari A.dll. File header akan terlihat seperti ini:

/* A.H */
#ifdef A_IMPL
   #define CLASS_DECL_A   __declspec(dllexport)
#else
   #define CLASS_DECL_A   __declspec(dllimport)
#endif

class CLASS_DECL_A CExampleA : public CObject
{ ... class definition ... };

// B.H
#ifdef B_IMPL
   #define CLASS_DECL_B   __declspec(dllexport)
#else
   #define CLASS_DECL_B   __declspec(dllimport)
#endif

class CLASS_DECL_B CExampleB : public CExampleA
{ ... class definition ... };
...

Ketika A.dll dibangun, itu dibangun dengan /D A_IMPL dan ketika B.dll dibangun, itu dibangun dengan /D B_IMPL. Dengan menggunakan simbol terpisah untuk setiap DLL, CExampleB diekspor dan CExampleA diimpor saat membangun B.dll. CExampleA diekspor saat membangun A.dll dan diimpor saat digunakan oleh B.dll (atau beberapa klien lain).

Jenis lapisan ini tidak dapat dilakukan saat menggunakan simbol AFX_EXT_CLASS dan _AFXEXT praprosesor bawaan. Teknik yang dijelaskan di atas memecahkan masalah ini dengan cara yang tidak seperti mekanisme yang digunakan MFC itu sendiri saat membangun DLL ekstensi MFC Aktif, Database, dan Jaringannya.

Tidak Mengekspor Seluruh Kelas

Ketika Anda tidak mengekspor seluruh kelas, Anda harus memastikan bahwa item data yang diperlukan yang dibuat oleh makro MFC diekspor dengan benar. Ini dapat dilakukan dengan mendefinisikan AFX_DATA ulang ke makro kelas spesifik Anda. Ini harus dilakukan kapan saja Anda tidak mengekspor seluruh kelas.

Contohnya:

/* A.H */
#ifdef A_IMPL
   #define CLASS_DECL_A  _declspec(dllexport)
#else
   #define CLASS_DECL_A  _declspec(dllimport)
#endif

#undef  AFX_DATA
#define AFX_DATA CLASS_DECL_A

class CExampleA : public CObject
{
   DECLARE_DYNAMIC()
   CLASS_DECL_A int SomeFunction();
   //... class definition ...
};

#undef AFX_DATA
#define AFX_DATA

Apa yang ingin Anda lakukan?

Apa yang ingin Anda ketahui lebih lanjut?

Lihat juga

Mengimpor dan Mengekspor