

Программирование на языке MFC
Мой второй блог в серии программирования
Метод CRuntimeClass::Load
Практически сразу после вызова ReadClassQ вызывает метод MapObject() с параметром NULL. Но обратите внимание, читатель, на то, что в случае чтения информации из архива создается не хэш-таблица, а МАССИВ указателей. Указатель на массив записывается в поле m_pLoadArray, которое, кстати, описано в одном объединении (union’e) с полем m_pStoreMap. После этого в архиве создается один элемент, в который записывается значение NULL. Естественно, счетчик элементов массива, т. е. значение поля m_nMapCount, тоже делается равным одному. Как и в случае сохранения информации в массиве, при аргументе, равном NULL метод больше ничего не делает. Таким образом, вызов метода MapObject() с параметром NULL при чтении из архива приводит к созданию и инициализации массива указателей.
Затем метод ReadClass() начинает работу в точном соответствии с тем списком правил, который мы сформировали в конце предыдущего раздела. В том случае, если считан тэг объекта, то метод записывает тэг объекта по адресу, переданному ему в качестве третьего аргумента, и возвращает значение NULL. Отметим этот факт – метод ReadClassQ в том случае, если из архива считан тэг объекта, возвращает значение NULL. У объекта схемы (версии) быть не может, поэтому мы не заполняем указатель на схему. Однако если из архива считан тэг класса, нам придется немного повозиться с этим тэгом.
Давайте рассуждать. Если встречен тэг класса, то какие случаи должны быть рассмотрены при этом? Наверное, должны быть рассмотрены два случая: 1) считан тэг ранее не встречавшегося класса и 2) считана ссылка на тэг ранее встречавшегося в процессе считывания класса. В том случае, если метод ReadClass() считал из архива тэг ранее не встречавшегося класса, то он должен загрузить информацию времени выполнения этого класса, после чего осуществить все необходимые проверки, верно? Информация времени выполнения загружается при помощи метода CRuntimeClass::Load(), исходный текст которого можно найти в файле агссоге.срр:
CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar,
UINT*’pwSchemaNum)
// loads a runtime class description
{
WORD nLen;
char szClassName[64]; CRuntimeClass* pClass;
WORD wTemp;
ar >> wTemp; *pwSchemaNum = wTemp; ar >> nLen;
if (nLen >= _countof(szClassName) ||
ar.Read(szClassName, nLen*sizeof(char)) !=
nLen*sizeof(char))
{
return NULL;
}
szClassName[nLen] = Л\0′;
// search app specific classes
AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
for (pClass = pModuleState->m_classList; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (IstrcmpA(szClassName,
pClass->m_lpszClassName) == 0)
{
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST); return pClass;
}
}
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
#ifdef _AFXDLL
// search classes in shared DLLs AfxLockGlobals(CRITJDYNLINKLIST);
for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL; pDLL = pDLL->m_pNextDLL)
{
for (pClass = pDLL->m_classList; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (IstrcmpA(szClassName,
pClass->m_lpszClassName) == 0)
{
AfxUnlockGlobals(CRIT_DYNLINKL1ST) ; return pClass;
}
}
}
AfxUnlockGlobals(CRIT_DYNLINKLIST); #endif
TRACE1 ("’Warning: Cannot load %hs from archive.
Class not defined.\n", szClassName);
return NULL; // not found
}
В тексте этого метода нужно обратить внимание на одну мелочь: для чтения названия класса выделяется буфер размером 64 байта. Следовательно, название класса не может быть длиннее 64 символов.
Похожие статьи: Load, Метод CRuntimeClass
