Недокументований клас CDocManager
Зв'язаний список шаблонів управляється внутрішнім екземпляром класу колекції MFC на ім'я CDocManager. Цей класс— недокументована можливість реалізації MFC. Проте, розуміння принципу дії даного класу може виявитися дуже корисним. Екземпляр цього класу створює в додатку об'єкт класу, похідного від CWinApp. Об'єкт класу CWinApp містить покажчик на об'єкт класу CDocManager. Перед завершенням роботи додаток викликає функцію-деструкцію класу CWinApp, яка видаляє всі об'єкти, створені під час виконання додатку (у тому числі і об'єкт CDocManager). Об'єкт CWinApp зберігає цей покажчик в змінній-членові m_pDocManager. Фактично, щоб дістати доступ до диспетчера документа, покажчик можна використовувати у будь-який момент.
Першорядним завданням диспетчера документів (document manager) є управління зв'язаним списком об'єктів шаблону. Диспетчер документів зберігає список у відкритій (public) змінній-членові m_TemplateList. Для перебору елементів списку можна використовувати код, подібний наступному:
void CSampleWinApp::IterateEveryTemplate ()
{
CDocManager* pManager = AfxGetApp()->m_pDocManager;
if (pManager == NULL) return;
POSITION pos = pManager->GetFirstDocTeraplatePosition();
while (pos != NULL)
{
// отримати наступний шаблон
CDocTemplate* pTemplate =pManager->GetNextDocTemplate(pos);
// тепер з даним покажчиком можна працювати
DoSomething(pTemplate);
}
}
Однією з найбільш важливих переваг, які забезпечує список шаблонів, є можливість отримання списку всіх активних документів. Для цього застосовується два цикли, вкладених один в одного. Перший цикл перебирає всі виявлені шаблони, а другий — всі документи, створені із застосуванням даного шаблону. Код, що реалізовує цю можливість, може виглядати таким чином:
void CSampleWinApp::IterateEveryDocument()
{
CDocManager* pManager = AfxGetApp()->m_pDocManager;
if (pManager == NULL) return;
POSITION posTemplate = pManager->GetFirstDocTemplatePosition();
while (posTemplate != NULL) {
// отримати наступний шаблон
CDocTemplate* pTemplate
= pManager->GetNextDocTemplate(posTemplate);
POSITION posDoc = pTemplate->GetFirstDocPosition{);
while (posDoc != NULL) {
CYourDocument* pThisOne
= (CSampleDocument*) GetNextDoc(posDoc);
// тут можна обробити кожен документ
pThisOne->SomeFunctionCall();
}
}
}
У обох фрагментах коди, щоб отримати покажчик диспетчер, спочатку слід звернутися до функції AfxGetApp і отримати покажчик на об'єкт додатку. Потім із змінної-члена m_jDDocManager отримуємо покажчик на диспетчер шаблонів. Фактично, це дещо більше, ніж просто привласнення, оскільки дані фрагменти коди є функціями-членами класу CSampleWinApp; тому цілком імовірно, що вони виявляться членами об'єкту, отриманого при зверненні до функції AfxGetApp. В принципі, замість цього можна було б звернутися до змінної-члена m_pDocManager безпосередньо. Але у зв'язку з очевидною неефективністю такого підходу використовуваний для доступу до інформації про об'єкт застосування, що виконується, функцію AfxGetApp.
Фрагменти коди, використовуючі функції-члени GetFirstDocTeraplatePosition і GetNextDocTemplate класу CDocManager, повинні виглядати знайомо, оскільки виконувані ними дії схожі на дії функцій-членів GetFirstViewPosition і TetNextView класу CDocument, який розглядався раніше. Основну роботу виконує функція GetNextDocTemplate, одержуюча покажчик на наступний документ (покажчик типу POSITION). Як можна відмітити, тут застосовується приведення типів часу виконання (runtime casting), оскільки перший фрагмент коди повинен передавати в другій покажчики на прості об'єкти класу CDocument як покажчики на клас CSampleDocument. Це був би дуже хороший привід продемонструвати застосування функції IsKindOf або макрокоманди бібліотеки MFC DYNAMIC_DOWNCAST, що дозволяють упевнитися в тому, що в результаті дійсного було отримано те, що і очікувалося. Але для простоти викладу код прикладів довелося скоротити.