Karşılıklı İçeri Aktarmalar
Başka bir yürütülebilir dosyaya dışarı veya içeri aktarma işlemi, içeri aktarma işlemleri karşılıklı (veya döngüsel) olduğunda karmaşıklıklar sunar. Örneğin, karşılıklı özyinelemeli işlevlere benzer şekilde iki DLL birbirinden sembolleri içeri aktarır.
Yürütülebilir dosyaları (genellikle DLL'ler) karşılıklı olarak içeri aktarmayla ilgili sorun, ikisi de ilki oluşturmadan oluşturulamıyor olmasıdır. Her derleme işlemi, giriş olarak diğer derleme işlemi tarafından üretilen bir içeri aktarma kitaplığı gerektirir.
Çözüm, yürütülebilir dosyayı oluşturmadan bir içeri aktarma kitaplığı oluşturan /DEF seçeneğiyle LIB yardımcı programını kullanmaktır. Bu yardımcı programı kullanarak, kaç DLL'nin dahil olduğu veya bağımlılıkların ne kadar karmaşık olduğu fark etmez, ihtiyacınız olan tüm içeri aktarma kitaplıklarını oluşturabilirsiniz.
Karşılıklı içeri aktarmaları işlemeye yönelik genel çözüm:
Her DLL'i sırayla alın. (Bazı siparişler daha uygun olsa da herhangi bir sipariş uygulanabilir.) Gerekli tüm içeri aktarma kitaplıkları varsa ve geçerliyse, yürütülebilir dosyayı (DLL) oluşturmak için LINK'i çalıştırın. Bu bir içeri aktarma kitaplığı oluşturur. Aksi takdirde, içeri aktarma kitaplığı oluşturmak için LIB'yi çalıştırın.
LIB'nin /DEF seçeneğiyle çalıştırılması, ile ek bir dosya oluşturur. EXP uzantısı. . Yürütülebilir dosyayı derlemek için EXP dosyasının daha sonra kullanılması gerekir.
Tüm içeri aktarma kitaplıklarını derlemek için LINK veya LIB kullandıktan sonra, önceki adımda derlenmemiş yürütülebilir dosyaları oluşturmak için LINK'i çalıştırın. İlgili .exp dosyasının LINK satırında belirtilmesi gerektiğini unutmayın.
DAHA önce DLL1 için içeri aktarma kitaplığı oluşturmak üzere LIB yardımcı programını çalıştırsaydınız, LIB dll1.exp dosyasını da üretmiş olurdu. DLL1.dlll oluştururken LINK'e giriş olarak DLL1.exp kullanmalısınız.
Aşağıdaki çizimde, karşılıklı olarak içeri aktaran iki DLL, DLL1 ve DLL2 için bir çözüm gösterilmektedir. 1. adım, DLL1'de /DEF seçeneği ayarlanmış şekilde LIB'yi çalıştırmaktır. 1. Adım DLL1.lib, içeri aktarma kitaplığı ve DLL1.exp oluşturur. 2. adımda, içeri aktarma kitaplığı DLL2'yi derlemek için kullanılır ve bu da DLL2'nin sembolleri için bir içeri aktarma kitaplığı oluşturur. 3. Adım, DLL1.exp ve DLL2.lib'i giriş olarak kullanarak DLL1'i oluşturur. DLL2'nin içeri aktarma kitaplığını derlemek için LIB kullanılmadığından DLL2 için bir .exp dosyasının gerekli olmadığını unutmayın.
İki DLL'yi Karşılıklı İçeri Aktarmalarla Bağlama
_AFXEXT sınırlamaları
MFC uzantısı DLL'lerinin birden çok katmanına sahip olmadığınız sürece MFC uzantı DLL'leriniz için ön işlemci simgesini kullanabilirsiniz _AFXEXT
. Kendi MFC uzantı DLL'lerinizdeki sınıflara çağrı yapan veya sınıflardan türetilen MFC uzantı DLL'leriniz varsa ve MFC sınıflarından türetilirseniz, belirsizliği önlemek için kendi ön işlemci sembolünüzü kullanmanız gerekir.
Sorun, Win32'de herhangi bir veriyi DLL'den dışarı aktarılacakmış gibi __declspec(dllexport)
ve __declspec(dllimport)
DLL'den içeri aktarılacaksa açıkça bildirmeniz gerektiğidir. tanımladığınızda_AFXEXT
, MFC üst bilgileri AFX_EXT_CLASS doğru tanımlandığından emin olur.
Birden çok katmanınız olduğunda, MFC uzantı DLL'leri yeni sınıfları dışarı aktarmanın yanı sıra başka bir MFC uzantısı DLL'sinden diğer sınıfları içeri aktarıyor olabileceğinden, AFX_EXT_CLASS gibi bir simge yeterli değildir. Bu sorunu çözmek için DLL'nin kendisini oluşturduğunuzu ve DLL'yi kullandığınızı gösteren özel bir ön işlemci simgesi kullanın. Örneğin, A.dll ve B.dll iki MFC uzantısı DLL'sini düşünün. Her biri sırasıyla A.h ve B.h'deki bazı sınıfları dışarı aktarır. B.dll A.dll sınıflarını kullanır. Üst bilgi dosyaları şuna benzer olacaktır:
/* 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 ... };
...
A.dll oluşturulduğunda ile /D A_IMPL
oluşturulur ve B.dll oluşturulduğunda ile /D B_IMPL
oluşturulur. Her DLL için ayrı simgeler kullanılarak dışarı CExampleB
aktarılır ve CExampleA
B.dll oluşturulurken içeri aktarılır. CExampleA
A.dll oluştururken dışarı aktarılır ve B.dll (veya başka bir istemci) tarafından kullanıldığında içeri aktarılır.
Bu katmanlama türü, yerleşik AFX_EXT_CLASS ve _AFXEXT
önişlemci simgeleri kullanılırken yapılamaz. Yukarıda açıklanan teknik, MFC'nin Etkin teknolojileri, Veritabanı ve Ağ MFC uzantısı DLL'lerini oluştururken kullandığı mekanizmadan farklı olmayan bir şekilde bu sorunu çözer.
Sınıfın Tamamı Dışarı Aktarılmıyor
Sınıfın tamamını dışarı aktarmadığınızda, MFC makroları tarafından oluşturulan gerekli veri öğelerinin doğru dışarı aktarıldığından emin olmanız gerekir. Bu, belirli bir sınıfın makrosna yeniden tanımlanarak AFX_DATA
yapılabilir. Bu, sınıfın tamamını dışarı aktarmadığınız her zaman yapılmalıdır.
Örneğin:
/* 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