Normal DLL'lerde Veritabanı, OLE ve Yuva Uzantı DLL'leri Kullanma
Normal DLL'den uzantı DLL kullanırken, eğer uzantı DLL normal DLL'in CDynLinkLibrary nesne zincirine bağlı değilse, bir veya daha fazla ilgili sorunla karşılaşabilirsiniz. MFC Veritabanı, OLE ve Yuvalar destek DLL'lerinin hata ayıklama sürümleri uzantı DLL olarak uygulandığından dolayı, bu MFC özelliklerini kullanıyorsanız kendi uzantı DLL'lerinizden birini açıkça kullanmıyorsanız bile benzer sorunlar görebilirsiniz. Bazı belirtiler şunlardır:
DLL uzantısında tanımlanan sınıf türünün bir nesnesinin serisini kaldırmayı denerken "Uyarı: CYourClass arşivden yüklenemiyor. mesajı Sınıf tanımlı değil." TRACE hata ayıklama penceresinde görünür ve nesne sıralanırken başarısız olur.
Kötü sınıfı gösteren bir özel durum oluşturulabilir.
Uzantı DLL'de saklanan kaynaklar yüklemede başarısız olur çünkü AfxFindResourceHandle NULL veya yanlış kaynak işleyicisi döner.
COleObjectFactory'nin DllGetClassObject, DllCanUnloadNow ve UpdateRegistry, Revoke, RevokeAll, ve RegisterAll üye işlevleri uzantı DLL'de tanımlanan sınıf üreticiyi bulmada başarısız olur.
AfxDoForAllClasses uzantı DLL'deki her sınıf için çalışmaz.
Standart MFC veritabanı, yuvalar veya OLE kaynakları yüklemede başarısız olur. Örneğin, AfxLoadString(AFX_IDP_SQL_CONNECT_FAIL), normal DLL, MFC Veritabanı sınıflarını düzgünce kullanırken bile boş dize döner.
Bu soruna çözüm, uzantı DLL'de CDynLinkLibrary nesnesi oluşturan bir başlangıç işlevi yazmak ve dışarı aktarmaktır. Bu başlangıç işlevini uzantı DLL'ini kullanan her normal DLL için tam olarak bir kez çağırın.
MFC OLE, MFC Veritabanı (veya DAO), veya MFC Yuva Desteği
Eğer normal DLL'inizde MFC OLE, MFC Veritabanı (veya DAO) veya MFC Yuvalar desteğinden herhangi birini kullanıyorsanız, MFC hata ayıklama uzantı DLL'leri MFCOxxD.dll, MFCDxxD.dll ve MFCNxxD.dll (xx sürüm numarasıdır) otomatik olarak bağlanır. Bu DLL'lerden kullandığınız her biri için ön tanımlı başlangıç işlevi çağırmalısınız.
Veritabanı desteği için, normal DLL'inizin CWinApp::InitInstance işlevine AfxDbInitModule çağrısı ekleyin. Bunun, temek sınıf çağrılarından veya MFCDxxD.dll'e erişen eklenmiş kodlardan önce olduğundan emin olun. Bu işlev parametre almaz ve void döner.
OLE desteği için, normal DLL'inizin CWinApp::InitInstance'ına AfxOleInitModule çağrısı ekleyin. COleControlModule InitInstance işlevinin zaten AfxOleInitModule'ü çağırdığını, bu sebeple eğer OLE denetimi oluşturuyorsanız ve COleControlModule kullanıyorsanız, bu çağrıyı AfxOleInitModule'e eklememeniz gerektiğini unutmayınız.
Yuvalar desteği için, normal DLL'inizin CWinApp::InitInstance'ına AfxNetInitModule çağrısı ekleyin.
MFC DLL'lerinin ve uygulamalarının sürüm derlemelerinin, veritabanı, yuva veya OLE desteği için ayrı DLL'ler kullanmadığını unutmayınız. Ancak, bu başlangıç işlevlerini sürüm modunda kullanmak güvenlidir.
CDynLinkLibrary Nesneleri
Bu konunun başında bahsedilen her bir işlem için, MFC istenen değeri veya nesneyi aramalıdır. Örneğin, seriyi kaldırma sürecinde, MFC arşivdeki nesnelerle uygun çalışma zamanı sınıflarını eşleştirmek için geçerli olarak kullanılabilen bütün çalışma zamanı sınıflarını aramalıdır.
Bu aramaların bir bölümü olarak, MFC kullanımdaki uzantı DLL'leri, CDynLinkLibrary nesneleri zincirinde yürüyerek arar. CDynLinkLibrary nesneleri yapım aşamasındayken otomatik olarak biz zincire iliştirilirler ve başlangıç sürecinde sırayla her uzantı DLL tarafından oluşturulurlar. Ek olarak, her modül (uygulama veya normal DLL) kendi CDynLinkLibrary nesneleri zincirine sahiptir.
Uzantı DLL'in CDynLinkLibrary zincirine bağlanması için, uzantı DLL'i kullanan her modülün bağlamında CDynLinkLibrary nesnesi oluşturmalıdır. Bu sebeple, eğer uzantı DLL normal DLL'den kullanılacaksa, CDynLinkLibrary nesnesi oluşturan dışarı aktarılmış bir başlangıç işlevi sağlamalıdır. Uzantı DLL'i kullanan her normal DLL dışarı aktarılmış başlangıç işlevini çağırmalıdır.
Eğer uzantı DLL sadece bir MFC uygulamasından (.exe) kullanılacaksa ve normal DLL'den hiç kullanılmayacaksa, CDynLinkLibrary nesnesini uzantı DLL'in DllMain'inde oluşturmak yeterlidir. Bu MFC DLL Sihirbazı uzantı DLL kodunun yaptığıdır. Uzantı DLL'i dolaylı olarak yüklerken, DllMain uygulama başlamadan önce yüklenir ve yürütülür. Herhangi bir CDynLinkLibrary oluşturma, MFC DLL'in bir MFC uygulaması için ayırdığı varsayılan zincire bağlanır.
Özellikle uzantı DLL bellekten dinamik olarak kaldırılacaksa, herhangi bir zincirde bir uzantı DLL'den birden çok CDynLinkLibrary nesnesinin olmasının kötü bir fikir olduğunu unutmayın. Herhangi bir modülden başlangıç işlevini birden çok defa çağırmayın.
Örnek Kod
Bu örnek kod normal DLL'in uzantı DLL'e dolaylı olarak bağlı olduğunu varsayar. Buna, normal DLL oluşturulurken uzantı DLL'in içeri aktarma kitaplığına (.lib) bağlanılarak ulaşılır.
Aşağıdaki satırlar uzantı DLL'in kaynağında olmalıdır:
// YourExtDLL.cpp:
// standard MFC extension DLL routines
#include "afxdllx.h"
static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// extension DLL one-time initialization
if (!AfxInitExtensionModule(extensionDLL, hInstance))
return 0;
}
return 1; // ok
}
// Exported DLL initialization is run in context of
// application or regular DLL
extern "C" void WINAPI InitYourExtDLL()
{
// create a new CDynLinkLibrary for this app
new CDynLinkLibrary(extensionDLL);
// add other initialization here
}
InitYourExtDLL işlevini dışarı aktardığınızdan emin olun. Bu __declspec(dllexport) kullanılarak veya DLL'inizin .def dosyasında aşağıdaki gibi yapılabilir:
// YourExtDLL.Def:
LIBRARY YOUREXTDLL
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD SINGLE
EXPORTS
InitYourExtDLL
Uzantı DLL'i kullanan her normal DLL'deki CWinApp türetilmiş sınıfın InitInstance üyesine çağrı ekleyin:
// YourRegularDLL.cpp:
class CYourRegularDLL : public CWinApp
{
public:
virtual BOOL InitInstance(); // Initialization
virtual int ExitInstance(); // Termination
// nothing special for the constructor
CYourRegularDLL(LPCTSTR pszAppName) : CWinApp(pszAppName) { }
};
BOOL CYourRegularDLL::InitInstance()
{
// any DLL initialization goes here
TRACE0("YOUR regular DLL initializing\n");
// wire any extension DLLs into CDynLinkLibrary chain
InitYourExtDLL();
return TRUE;
}