TN058: mfc Modül durumu uygulaması

Bu teknik not mfc "modülü devlet" yapıları uygulanması anlatılmaktadır. mfc kullanılarak paylaşılan dll Dll'lerden Modül durumu uygulama anlayışı önemlidir (ya da ole işlem sunucusu).

Bu notu okumadan önce lütfen "Yönetme devlet veri mfc modüller için" başvuru yeni belgeler oluştururken, Windows ve Gösterim Visual c++ programlama Kılavuzu. Bu makale, önemli kullanım bilgileri ve bu konu hakkında genel bilgi içerir.

Genel bakış

Mfc durum bilgilerini üç tür vardır: Modül durumu, işlem durumu ve iş parçacığı durumu. Bazen bu durum türleri birleştirilebilir. Örneğin, MFC'ın kolu haritalar hem modülü yerel iş parçacığı yerel vardır. Böylece, her biri kendi konuları farklı haritalar iki farklı modül.

İşlem durumu ve iş parçacığı durumu benzer. Bu veri öğelerinin geleneksel genel değişkenler olabilirdi, ama olması gereken belirli bir işlemin belirli ya da uygun Win32s destek veya uygun çoklu destek için konuyu şeyler vardır. Bu madde ve onun istenen semantiği işlem ve iş parçacığı sınırları konusunda verilen veri öğesi uyuyor hangi kategoriye bağlıdır.

Gerçekten küresel devlet ya da yerel işlem veya iş parçacığı yerel devlet içerebilir Modül durumu benzersizdir. Ayrıca kolayca değiştirilebilir.

Modül durumu değiştirme

Her iş parçacığı "geçerli" veya "etkin" modül durumunu gösteren bir işaretçi içeren (doğal olarak, işaretçi MFC'ın iş parçacığı yerel, eyalet parçasıdır). Yürütme iş parçacığı bir uygulama içine bir ole denetimi veya dll ya da bir ole denetimi geri bir uygulamaya çağırma çağırma gibi bir modül sınırı geçtiğinde bu işaretçisi değiştirilir.

Geçerli Modül durumu, AfxSetModuleStatearayarak anahtarlanır. Çoğunlukla, asla doğrudan API ile ilgileneceğiz. mfc, birçok durumda, arayacak o sizin için (at WinMain, ole giriş noktaları, AfxWndProc, vs.). Bu herhangi bir bileşen yazmak içinde özel bir statik olarak bağlayarak WndProcve özel WinMain (veya DllMain) yapılır hangi Modül durumu geçerli olmalıdır bilir. dllmodul bir göz alarak bu kodu görebilirsiniz.cpp ya da appmodul.cpp mfc\src Rehberi.

Bu modül durumunu ayarlamak ve sonra bunu geri değil koymak istediğiniz nadirdir. Çoğu zaman, "kendi modül itmek istiyorum" olarak geçerli bir devlet ve sonra sonra "özgün içeriği geri pop". Bu makro afx_manage_state , özel sınıf AFX_MAINTAIN_STATE tarafından yapılır.

CCmdTarget modül durumunu değiştirme'yi desteklemek için özel özelliklere sahiptir. Özellikle, bir CCmdTarget kök sınıf ole Otomasyonu ve ole com için giriş noktaları kullanılır. Başka bir giriş noktası hangi tarihlerde sistemine maruz, bu giriş noktaları doğru modül durumunu ayarlamak gerekir. Verilen CCmdTarget ne "doğru" modülü devlet olmalıdır nasıl biliyor? Cevap onu hatırlar"inşa edilmiştir"geçerli"Modül durumu nedir" ise şekilde ayarlayabilirsiniz "daha sonra ne zaman değerini geçerli Modül durumu o hatırladı". Bunun sonucunda, belirli bir CCmdTarget nesnesi ile ilişkili modülü ne zaman was constructed nesne geçerli Modül durumu durumudur. Bir InProc sunucusu yükleme, nesne oluşturma ve kendi yöntemlerini basit bir örnek verelim.

  1. LoadLibrary kullanarak ole tarafından yüklenen dll.

  2. RawDllMain ilk olarak adlandırılır. O bilinen statik modül devlet için dll modülünü durumunu ayarlar. Bu nedenle RawDllMain dll için statik olarak bağlı.

  3. Bizim nesnesi ile ilişkilendirilmiş sınıf fabrikası kurucusu olarak bilinir. COleObjectFactory CCmdTarget türetilmiştir ve bunun sonucunda, hangi modülü durumunda bunun örneği hatırlar. Bu önemli bir — nesne sınıfı fabrika sorulduğunda, şimdi geçerli yapmak için hangi modülü durumu bilir.

  4. DllGetClassObject sınıfı fabrika almaya denir. mfc bu modül ile ilişkilendirilmiş sınıf fabrika listesi arar ve döndürür.

  5. COleObjectFactory::XClassFactory2::CreateInstance denir. Nesne oluşturma ve bunu dönmeden önce bu işlev için adım 3 (ne zaman COleObjectFactory örneği geçerli bir) geçerli Modül durumu modülü durumunu ayarlar. Bu method_prologue içinde yapılır.

  6. Nesne oluşturulur, bu çok CCmdTarget türevi ve hangi modül durumunu etkin COleObjectFactory aynı şekilde hatırladım, yani bu yeni nesne yok. Nesne geçmek için hangi modülü durumu bilir şimdi zaman denir.

  7. İstemci, CoCreateInstance çağrı aldı ole com nesnesinde bir işlevi çağırır. Nesne adı verilen bu method_prologue sadece COleObjectFactory gibi modülü durumuna geçmek için kullanır.

Gördüğünüz gibi oluşturulan modül durumu nesneden nesneye yayılır. Ayarladığınızdan modülü devlet olması önemlidir. Ayarlanmazsa, dll veya com nesnesi ile bir mfc uygulaması, aradığını kendi kaynakları bulmak mümkün olabilir veya mutsuz başka yollarla başarısız olabilir kötü etkileşebilen.

Not belirli türde dll, özellikle "mfc uzantısı" dll kendi RawDllMain modülü devlet geçiş yoktur (aslında, genellikle bile bir RawDllMainyok). Bunun nedeni, "aslında onları kullanan uygulamada mevcut sanki gibi onlar were" davranmaya yöneliktir. Çalışan uygulama çok bir parçası olduklarını ve bu uygulamanın genel durumu değiştirmek için onların niyeti olduğunu.

Ole Denetimleri ve diğer DLL çok farklıdır. Çağıran uygulama durumu değiştirmek istemiyorsanız; onları çağıran uygulamanın bir mfc uygulaması bile olmayabilir ve öylesine orada-ebilmek var olmak değiştirmek için hiçbir devlet. Bu modül durumunu değiştirme'yi icat edildi nedenidir.

İçin verilen işlevlerini gibi bir dll, iletişim kutusunda başlatan bir dll işlevinin başına aşağıdaki kodu ekleyin gerek:

Afx_manage_state (AfxGetStaticModuleState ())

Bu AfxGetStaticModuleState döndürülen geçerli kapsamı sonuna kadar devlet ile geçerli Modül durumu değiştirir.

afx_module_state makro kullanılmamışsa dll kaynaklarında sorunlar ortaya çıkar. Varsayılan olarak, mfc kaynak şablon yüklemek için ana uygulama kaynak tanıtıcısı kullanır. Bu şablon, aslında dll saklanır. MFC'ın Modül durumu bilgilerini afx_module_state macro geçildi değil kök nedenidir. Kaynak tanıtıcısı MFC'ın modülü durumundan kurtarılır. Modül durumu değiştirme değil neden kullanılacak yanlış Kaynak tanıtıcısı.

afx_module_state her işlev dll içinde koymak gerekmez. Örneğin, InitInstance mfc modülü devlet önce otomatik olarak geçer çünkü uygulamayı olmadan afx_module_state mfc kod çağrılabilir InitInstance ve sonra geri sonra anahtarları InitInstance verir. Tüm ileti göster işleyicileri için geçerlidir. Düzenli DLL'leri aslında herhangi bir iletiyi yönlendirmeden önce modül durumunu otomatik olarak geçer bir özel ana pencere yordamı var.

İşlem yerel veri

İşlemi yerel veri, Win32 dll modeli için zorluk olmasaydı böyle büyük endişe olmaz. Win32'de tüm DLL'leri küresel verilerini, hatta birden çok uygulama tarafından yüklenen paylaşmak. Bu tamamen burada her DLL'nin DLL'ye verdiği her işlemde, veri alanı ayrı bir kopyasını alır "gerçek" Win32 dll veri modeli farklıdır. Karmaşıklığa için ayrılan bir Win32 dll içinde öbek üzerindeki veri aslında belirli (en azından sahiplik gider olarak kadarıyla) işlemidir. Aşağıdaki verileri ve kodu düşünün:

statik CString strGlobal; / / Dosya kapsamında

__declspec(dllexport) void SetGlobalString(LPCTSTR lpsz)
{
   strGlobal = lpsz;
}

__declspec(dllexport)
void GetGlobalString (lpctstr lpsz, int cb)
{
   lstrcpyn (lpsz, strGlobal, cb);
}

Yukarıdaki kod içinde bir dll içinde bulunuyorsa, ve dll iki süreç a ve b (aslında iki tane aynı uygulama olabilir) yüklendiğinde ne olur düşünün. Bir arama SetGlobalString("Hello from A") . Sonuç olarak, bellek CString veri işlem a. Keep CString kendisi genel ve her iki a-görünür unutmayın kapsamında tahsis edilen ve b. Şimdi b çağrı GetGlobalString(sz, sizeof(sz)) . B bir dizi verileri görmek mümkün olacak. Bunun nedeni, Win32s Win32 gibi işlemler arasındaki hiç koruma sunar. Böylece ilk sorun var; birçok durumda farklı bir uygulama tarafından sahip olunan kabul edilen genel verileri etkileyen bir uygulama olmasını arzu değil.

Ama beklemek — daha fazla sorun vardır. Diyelim ki, şimdi o çıkar. a çıktığında, tarafından kullanılan bellek ' strGlobal ' dizesi için sistem kullanılabilir yapılır — süreç a tarafından ayrılan tüm bellek işletim sistemi tarafından otomatik olarak, serbest. Çünkü CString yıkıcı çağrıldığını serbest değil; o henüz olarak değil. Sadece serbest kalır çünkü ayrılan uygulama sahneyi terk etti. Şimdi eğer b denilen GetGlobalString(sz, sizeof(sz)) , geçerli veri alamayabilirsiniz. Başka bir uygulama bellek başka bir şey için kullanmış olabilirsiniz.

Açıkça orada'bir problem burada. mfc 3.x, iş parçacığı yerel depolama (tls) adı verilen bir teknik kullanılır. mfc 3.x, düz-se bile o denilen değil bir tls dizini altında Win32s, gerçekten bir işlemi yerel depolama dizini davranan tahsis etmek ve ardından tüm verileri bu tls dizin tabanlı ba?vurursunuz. Bu tls dizin Win32 iş parçacığı yerel veri depolamak için kullanılan benzer (aşağıda bu konuda daha fazla bilgi için bkz). Bunun nedeni, işlem başına en az iki tls Endeksleri yararlanmak her mfc dll. Birçok ole denetim dll (OCXs) yüklemek için hesap size hızla tls Endeksleri (vardır yalnızca 64) üzerinden çalıştırın. Ayrıca, tüm bu verileri tek bir yapıda tek bir yerden yere mfc vardı. Çok Genişletilebilir değildi ve tls Endeksleri kullanımı açısından ideal değildi.

Mfc 4.x, bu size "işlemi yerel olması gereken verileri sarın" sınıf şablonları kümesi yöneliktir. Örneğin, yukarıda bahsedilen sorunu yazarak sabit:

yapı CMyGlobalData: Genel CNoTrackObject
{
   CString strGlobal;
};
CProcessLocallt;CMyGlobalData > globalData;

__declspec(dllexport) void SetGlobalString(LPCTSTR lpsz)
{
   globalData - > strGlobal = lpsz;
}

__declspec(dllexport)
void GetGlobalString (lpctstr lpsz, int cb)
{
   lstrcpyn (lpsz, globalData - > strGlobal, cb);
}

Mfc bu iki adımda uygular. Birincisi, orada bir katman üzerine Win32 Tls * olursa olsun kaç DLL'ler, eğer işlem başına sadece iki tls dizinler kullanan API'leri (TlsAlloc, TlsSetValue, Tls&GetValue, vb). İkinci, CProcessLocal şablon bu verilere erişmek için sağlanır. Bu işleç-gt geçersiz kılar; hangi ne Yukarıda gördüğünüz sezgisel sözdizimi sağlanmıştır. Tarafından sarılmış tüm nesneleri CProcessLocal sayfasından elde edilebilir CNoTrackObject . CNoTrackObject bir alt düzey ayırıcısı sağlar (LocalAlloc/LocalFree) ve bir sanal yıkıcı gibi bu işlem sonlandırıldı zaman mfc otomatik işlemi yerel nesneleri yok edebilir. Gerekirse ek Temizleme gibi nesneleri özel bir yıkıcı olabilir. Çünkü derleyici katıştırılmış CString nesneyi yok etmek için bir varsayılan yıkıcı oluşturur Yukarıdaki örnekte, gerektirmez.

Bu yaklaşım diğer ilginç faydası vardır. Sadece tüm olan CProcessLocal nesneleri otomatik olarak tahrip gerekene kadar onlar inşa edilir değil. CProcessLocal::operator-gt; ilişkili bir nesne ilk kez o denir ve hiçbir erken başlatmak. Yukarıdaki örnekte, yani ' str&Global ' dize değil inşa kadar ilk kez SetGlobalString ya da GetGlobalString denir. Bazı durumlarda, bu dll başlatma süresini azaltmak yardımcı olabilir.

İş parçacığı yerel veri

Verileri için belirli bir iş parçacığı yerel olmalıdır benzer yerel verileri işlemek için iş parçacığı yerel veriler kullanılır. Başka bir deyişle, bu verilere erişen her iş parçacığı için verileri ayrı bir örneğini gerekir. Bu kapsamlı eşitleme mekanizmaları yerine birçok kez kullanılabilir. Verileri birden çok iş parçacığı tarafından paylaşılmış olması gerekmez, bu tür mekanizmalar pahalı ve gereksiz olabilir. Biz CString object (Yukarıdaki örnek gibi) olduğunu varsayalım. Biz bu konuyu yerel ile sarma yapabilir bir CThreadLocal şablonu:

yapı CMyThreadData: Genel CNoTrackObject
{
   CString strThread;
};
CThreadLocallt;CMyThreadData > threadData;

void MakeRandomString()
{
   / / a tür kart shuffle (aynı zamanda büyük bir değil)
   CString & str = threadData - > strThread;
   Str.Empty();
   (str.GetLength()! = 52)
   {
      tchar ch = rand() % 52 + 1;
      Eğer (str.Find(CH) < 0)
         Str += ch; / / değil bulundu, ekleyin
   }
}

Eğer MakeRandomString denilen iki farklı iş parçacıklarının her "dizesini farklı şekillerde diğer engel olmadan karıştırmak". Bunun nedeni var aslında bir strThread örneği başına tek bir küresel örneği yerine iplik.

Başvuru CStrin&g adresi bir kez döngü tekrarında bir kez yerine yakalamak için nasıl kullanıldığını unutmayın. Döngü kodu ile yazılmış threadData-gt;strThread her yerde ' str ' kullanılır, ancak kod yürütülmesine çok daha yavaş olacaktır. Bu tür başvurular döngüler oluştuğunda verilere bir başvuru önbelleğe almak iyi.

CThreadLocalSınıf şablonu kullanır aynı mekanizmaları, CProcessLocal yok ve uygulama teknikleri.

Teknik notlar numarasına göre |nbsp; Teknik notlar kategorisine göre

Index