Aracılığıyla paylaş


TN058: Modül durumu mfc uygulaması

Not

İlk çevrimiçi belgelerinde yer almıştır beri aşağıdaki teknik Not güncelleştirilmedi.Sonuç olarak bazı yordamlar ve konuları eski veya yanlış.En son bilgiler için çevrimiçi belgelere dizini ilgilendiğiniz konu aramak önerilir.

Bu teknik Not mfc "Modül durumu" yapıları uygulaması açıklar. Bir dll Dll'lerden mfc kullanılarak paylaşılan Modül durumu uygulaması anlamak önemlidir (veya ole işlem sunucusu).

Bu not okumadan önce "Yönetme durumu verileri, mfc modülleri için" başvuru Yeni belgeler oluşturma, Windows ve görünümleri. Bu makalede, önemli kullanım bilgileri ve bu konu hakkında genel bilgiler içerir.

Genel Bakış

mfc durum bilgileri üç tür vardır: Modül durumu, işlem durumu ve iş parçacığı durumu. Bazen bu durum türlerini birleştirilebilir. Örneğin, işleyici eşlemeleri MFC'ın yerel modül hem iş parçacığı yerel ' dir. Böylece, farklı eşlemeleri her kendi iş parçacığı iki farklı modül.

İşlem durumu ve iş parçacığı durumu benzer. Bu veri öğelerinin geleneksel genel değişkenler olmuştur, ancak olması gereken belirli bir işlemi belirli veya uygun Win32s desteği için veya uygun çoklu kullanım desteği için iş parçacığı almaktadır. Bu madde ve işlem ve iş parçacığı sınırları için istenen kendi semantiği verilen veri öğesi tam hangi kategoriye bağlıdır.

Gerçekten genel durumu ya da yerel bir işlem veya iş parçacığı yerel durumunu içeren modül durumu benzersizdir. Buna ek olarak, bunu 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çerir (edilebileceği gibi işaretçiyi MFC'ın yerel iş parçacığı durumu 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 çağırarak geçti AfxSetModuleState. Çoðunlukla, hiçbir zaman doğrudan API ile ilgilenme. mfc, çoğu durumda çağrısı, sizin için (WinMain, ole giriş noktaları, en AfxWndProc, vb..). Bu yaz özel bir statik olarak bağlayarak herhangi bir bileşeni yapılır WndProcve özel bir WinMain (veya DllMain) hangi Modül durumu geçerli bilir. Bu kodu, dllmodul bakarak görebilirsiniz.cpp veya appmodul.cpp mfc\src dizininde.

Modül durumunu ayarlayabilirsiniz ve daha sonra onu geri değil istediğiniz seyrektir. Çoğu zaman "kendi modülü itme" istediğiniz gibi geçerli bir durum ve tamamladıktan sonra sonra "özgün içeriği geri pop". Bu makro tarafından yapılır afx_manage_state ve özel sınıf AFX_MAINTAIN_STATE.

CCmdTargetModül durumu geçişi desteklemek için bazı özelliklere sahiptir. Özellikle, bir CCmdTarget ise kök kullanılan sınıf ole Otomasyonu ve ole com için giriş noktaları. Başka bir giriş noktası gibi sistem gözüken bu giriş noktaları doğru Modül durumu ayarlamalısınız. Nasıl mı bir verilen CCmdTarget "doğru" Modül durumu ne olması gerektiğini biliyor? Yanıt, "bunu oluşturulur,"geçerli"Modül durumu nedir hatırlar", mümkün olduğunu "sonraki olduğunda, geçerli Modül durumu değeri söyledim" set adlı olur. Sonuç olarak Modül durumu, bir verilen CCmdTarget nesne ilişkili olan nesne oluþturulduðuna zaman geçerli Modül durumu. InProc sunucusu yüklenirken, nesne oluşturma ve yöntemlerini çağıran basit bir örnek alın.

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

  2. RawDllMain ilk olarak adlandırılır. Bilinen statik Modül durumu modülünün durumunu dll için ayarlar. Bu nedenle RawDllMain dll statik olarak bağlı.

  3. Bizim nesnesiyle ilişkilendirilmiş sınıf fabrikası kurucusu olarak bilinir. COleObjectFactorytüretilir CCmdTarget ve hangi modülü il örneği oluşturulduktan sonucu olarak hatırlar. Önemli — sınıf üreteci nesneleri oluşturmak için sorulduğunda, şimdi geçerli hale getirmek için hangi modülü durumu bilir.

  4. DllGetClassObjectsınıf üreteci elde etmek denir. mfc, bu modülü ile ilişkilendirilmiş sınıf Fabrika listesi arar ve bunu döndürür.

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

  6. Nesne oluşturulduğunda, çok uzun bir CCmdTarget türetilen ve aynı şekilde COleObjectFactory söyledim hangi modül durumunu etkin, böylece bu yeni nesne yapar. Nesne geçiş yapmak için hangi modülü durumu bilir şimdi zaman olarak adlandırılır.

  7. İstemci, alınan ole com nesnesinde bir işlevi çağırır, CoCreateInstance çağırın. Nesne çağrıldığında kullanan METHOD_PROLOGUE Modül durumu tıpkı geçmek için COleObjectFactory yapar.

Gördüğünüz gibi oluşturuldukları sırada Modül durumu nesneden nesneye yayılır. Modül durumu uygun şekilde ayarlamak önemlidir. Ayarlanmazsa, dll veya com nesnesi düzgün çağırmadan, kendi kaynaklarını bulamadı veya miserable başka yollarla başarısız olabilir bir mfc uygulaması ile etkileşime girebilir.

Not belirli türde dll, özellikle "mfc uzantısı" dll modülünü durumunda geçiş değil kendi RawDllMain (aslında, bunlar genellikle bile olmayan bir RawDllMain). Aslında bunları kullanan uygulama var "gibi" davranmasını hedeflenen olmasıdır. Çok çalışan uygulama parçası ve uygulamanın genel durumunu değiştirmek için kendi amacınıza olur.

ole denetimleri ve diğer dll çok farklıdır. Çağıran uygulamanın durumunu değiştirmek istemiyor; onları çağıran uygulama mfc uygulaması bile olmayabilir ve bu nedenle olabilir değiştirmek durumuna. Modül durumu değiştirme bulunmuştur nedeni budur.

Bir dll dosyanızın iletişim kutusunda başlatır gibi bir dll tarafından verilen işlevleri için işlevin başına aşağıdaki kodu eklemek gerekir:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

Bu dönen durumuyla geçerli modül durumunu değiştirir AfxGetStaticModuleState geçerli kapsamı sonuna kadar.

Dll kaynaklarında bir sorun varsa oluşur AFX_MODULE_STATE makro kullanılmaz. Varsayılan olarak, mfc kaynak tanıtıcısı ana uygulamanın kaynak şablon yüklemek için kullanır. Bu şablon gerçekten dll dosyasında depolanır. MFC'ın modülü durum bilgisi olarak geçildi değil, kök neden olan AFX_MODULE_STATE makro. Kaynak tanıtıcısı, MFC'ın modülü durumundan kurtarıldı. Modül durumu değiştirme değil, kullanılacak yanlış Kaynak tanıtıcısı neden olur.

AFX_MODULE_STATEher işlev dll içinde koymak gerekmez. Örneğin, InitInstance mfc kodu uygulama tarafından çağrılan AFX_MODULE_STATE mfc Modül durumu önce otomatik olarak geçer çünkü InitInstance ve daha sonra geri sonra anahtarları InitInstance verir. Aynı tüm ileti eşleme işleyicileri için de geçerlidir. Normal DLL'leri aslında herhangi bir iletiyi yönlendirmeden önce modül durumunu otomatik olarak geçer bir özel ana penceresinin yordam vardır.

Yerel veri işleme

Yerel veri işlem, Win32 dll modeli zorluk için eklenmiştir mükemmel gibi önemli olmayacaktır. Win32s genel verilerine bile birden çok uygulama tarafından yüklendiğinde tüm dll dosyaları paylaşın. Burada her dll DLL'i ekler her işlem, veri alanı ayrı bir kopyasını alır "gerçek" Win32 dll veri modeli, bu çok farklıdır. Karmaşıklığı eklemek için veri Win32 dll içinde öbek üzerindeki tahsis aslında belirli (en az en sahiplik gider gibi) işlemidir. Aşağıdaki verileri ve kodu göz önünde bulundurun:

static CString strGlobal; // at file scope

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

__declspec(dllexport)
void GetGlobalString(LPCTSTR lpsz, size_t cb)
{
   StringCbCopy(lpsz, cb, strGlobal);
}

Yukarıdaki kod dll içinde bulunur, ve a ve b (aslında, aynı uygulamanın iki tane olabilir) iki işlemler tarafından dll yüklendiğinde ne olacağını düşünün. A calls SetGlobalString("Hello from A"). Bellek için sonuç olarak ayrılan CString veri işlem a. bağlamında Unutmayın CString kendisini geneldir ve her iki a görünür ve b. Şimdi b çağıran GetGlobalString(sz, sizeof(sz)). B a kümesi verileri görmek mümkün olacaktır. Bunun nedeni Win32s Win32 yaptığı gibi işlemler arasında koruma sunar. İlk sorun olan; Çoğu zaman farklı bir uygulama tarafından gözüktüğü kabul genel verileri etkileyen bir uygulama olmasını arzu değil.

Ek sorunlar bulunmaktadır. Şimdi bir çıkar diyelim. a çıktığında, tarafından kullanılan bellek 'strGlobal' dizesi sistemi için kullanılabilen yapılan — işlem a tarafından ayrılmış tüm belleği işletim sistemi tarafından otomatik olarak, serbest. Çünkü serbest bırakılmaz CString yıkıcı olarak adlandırılır; henüz adlı alınmadı. Yalnızca serbest, tahsis uygulaması Sahne bıraktığından. b adı verilen, şimdi GetGlobalString(sz, sizeof(sz)), geçerli veri alamayabilirsiniz. Başka bir uygulama, belleğin bir şey için kullanmış olabilir.

Belirgin bir sorun bulunmaktadır. mfc 3.x, iş parçacığı yerel depolama (tls) adı verilen bir teknik kullanılır. mfc 3.x, çağrılmaz olsa, gerçekten bir işlemi yerel depolama dizini davranan Win32 altında tls dizin ayırmak ve tls dizini temel alan tüm veriler daha sonra baþvurursunuz. Bu Win32 iş parçacığı yerel veri depolamak için kullanılan tls dizin benzer (Aşağıda bu konu hakkında daha fazla bilgi için bkz.). Bu işlem başına en az iki tls indices yararlanmalarına her mfc dll kaynaklanıyor. Birçok ole Denetim dll (OCXs) yüklemek için hesap, hızla (vardır yalnızca 64) tls indices dışında çalıştırın. Buna ek olarak, tüm bu verileri tek bir yapıda, tek bir yerde yerleştirmek mfc vardı. Bu oldukça genişletilebilir değil ve tls indices kullanımı açısından ideal değildi.

mfc 4.x Bu, "yerel işlem olması gereken veri kaydırabilirsiniz" sınıf şablonları kümesi yöneliktir. Örneğin, yukarıda bahsedilen sorun yazarak tamir edilemez:

struct CMyGlobalData : public CNoTrackObject
{
   CString strGlobal;
};
CProcessLocal<CMyGlobalData> globalData;

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

__declspec(dllexport)
void GetGlobalString(LPCTSTR lpsz, size_t cb)
{
   StringCbCopy(lpsz, cb, globalData->strGlobal);
}

mfc bu iki adımda uygular. Uğrar Win32 üstünde bir katman Tls * API'leri (TlsAlloc, TlsSetValue, TlsGetValue, vb.) sahip kaç DLL'leri ne olursa olsun, işlem başına yalnızca iki tls dizinler kullanın. İkinci, CProcessLocal şablonu bu verilere erişmesine izin verilir. Geçersiz, operatör - kılar > Yukarıda gördüğünüz sezgisel bir sözdizimi sağlar ne olduğu. Tarafından sarılan tüm nesneleri CProcessLocal den türetilmiş olması CNoTrackObject. CNoTrackObjectalt düzey ayırıcısı sağlar (LocalAlloc/LocalFree) ve sanal yıkıcı işlemi kesildiğinde mfc otomatik olarak işlem yerel nesneleri yok edebilir olduğunu. Ek temizleme, bu tür nesneleri özel yıkıcı olabilir. Derleyici katıştırılmış yıkmak için varsayılan yıkıcı oluşturacak beri Yukarıdaki örnekte, gerektirmeyen CString nesnesi.

Bu yaklaşım diğer ilginç faydası vardır. Yalnızca tüm olan CProcessLocal nesneleri otomatik olarak görmesi gerekene kadar bunlar oluşturulur değil. CProcessLocal::operator->ilişkili bir nesne ilk kez buna denir ve dolması oluşturulmaz. Yukarıdaki örnekte, anlamı 'strGlobal' dize değil oluşturulması kadar ilk kez SetGlobalString veya GetGlobalString denir. Bazı durumlarda bu dll başlatma süresini azaltmak yardımcı olabilir.

İş parçacığı yerel veri

Verileri belirli bir iş parçacığı yerel yerel verileri işlemek için benzer iş parçacığı yerel veri kullanılır. Diğer bir deyişle, veriye erişen her iş parçacığı için ayrı bir veri örneği gerekir. Bu kapsamlı eşitleme mekanizmaları yerine birçok kez kullanılabilir. Verileri birden çok iş parçacığı tarafından paylaşılacak gerekmiyorsa, bu tür mekanizmaları pahalı ve gereksiz olabilir. Biz vardı varsayalım bir CString nesne (çok Yukarıdaki örneğe benzer). Biz, iş parçacığı yerel ile kaydırma yapabilir bir CThreadLocal şablonu:

struct CMyThreadData : public CNoTrackObject
{
   CString strThread;
};
CThreadLocal<CMyThreadData> threadData;

void MakeRandomString()
{
   // a kind of card shuffle (not a great one)
   CString& str = threadData->strThread;
   str.Empty();
   while (str.GetLength() != 52)
   {
      unsigned int randomNumber;
      errno_t randErr;
      randErr = rand_s( &randomNumber );
      if ( randErr == 0 )
      {
         TCHAR ch = randomNumber % 52 + 1;
         if (str.Find(ch) < 0)
            str += ch; // not found, add it
      }
   }
}

MakeRandomString Çağrıldı iki farklı ilişkilerden her "dizesi farklı şekillerde birbirleriyle etkilemeksizin karıştırmak". Olduğundan bu, gerçekten bir strThread örneği başına yalnızca bir genel örneği yerine iş parçacığı.

Not başvuru yakalamak için nasıl kullanılacağını CString adresi bir kez yerine bir kez döngü tekrarında. Döngü kodu ile yazılmış threadData->strThread her yerde 'str' kullanılır, ancak kod yürütülmesine daha yavaş olacaktır. Bu tür başvurular döngüleri içinde oluştuğunda verilere bir başvuru önbelleğe almak en iyisidir.

CThreadLocal Sınıf şablonu aynı mekanizmalar kullanır, CProcessLocal mu ve uygulama teknikleri.

Ayrıca bkz.

Diğer Kaynaklar

Teknik notlar numarasına göre

Kategoriye göre teknik notlar