<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Программирование на языке MFC &#187; Load</title>
	<atom:link href="http://www.programmfc.ru/tag/load/feed" rel="self" type="application/rss+xml" />
	<link>http://www.programmfc.ru</link>
	<description>Мой второй блог в серии программирования</description>
	<lastBuildDate>Mon, 08 Feb 2010 19:34:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Метод Abort</title>
		<link>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-abort-2.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-abort-2.html#comments</comments>
		<pubDate>Mon, 08 Feb 2010 19:31:27 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Приложения]]></category>
		<category><![CDATA[Load]]></category>
		<category><![CDATA[Метод Abort]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-abort-2.html</guid>
		<description><![CDATA[Тем не менее, мы может прекратить работу архива в любое время при помощи метода Abort(), исходный текст которого находится в файле агссоге.срр:
void CArchive::Abort() {
ASSERT(m_bDirectBuffer &#124;&#124;
m_lpBufStart == NULL &#124;&#124; AfxIsValidAddress(m_lpBufStart,
m_lpBufMax &#8211; m_lpBufStart, IsStoring()));
ASSERT(m_bDirectBuffer &#124;&#124;
m_lpBufCur == NULL &#124;&#124; AfxIsValidAddress(m_lpBufCur,
m_lpBufMax &#8211; m_lpBufCur, IsStoring()));
// disconnect from the file mjpFile = NULL;
if (!m_bUserBuf) {
ASSERT(!m_bDirectBuffer); delete[] m_lpBufStart; m_lpBufStart = NULL; m_lpBufCur [...]]]></description>
			<content:encoded><![CDATA[<p>Тем не менее, мы может прекратить работу архива в любое время при помощи метода Abort(), исходный текст которого находится в файле агссоге.срр:</p>
<p><b>void CArchive::Abort() {</b></p>
<p><b>ASSERT(m_bDirectBuffer ||</b></p>
<p><b>m_lpBufStart == NULL || AfxIsValidAddress(m_lpBufStart,</b></p>
<p><b>m_lpBufMax &#8211; m_lpBufStart, IsStoring()));</b></p>
<p><b>ASSERT(m_bDirectBuffer ||</b></p>
<p><b>m_lpBufCur == NULL || AfxIsValidAddress(m_lpBufCur,</b></p>
<p><b>m_lpBufMax &#8211; m_lpBufCur, IsStoring()));</b></p>
<p><b>// disconnect from the file mjpFile = NULL;</b></p>
<p><b>if (!m_bUserBuf) {</b></p>
<p><b>ASSERT(!m_bDirectBuffer); delete[] m_lpBufStart; m_lpBufStart = NULL; m_lpBufCur = NULL;</b></p>
<p>}</p>
<p><b>delete m_pSchemaMap; m_pSchemaMap = NULL;</b></p>
<p><b>// m_pStoreMap and m_pLoadArray are unioned, // so we only need to delete one</b></p>
<p><b>ASSERT((CObject*)m_pStoreMap == (CObject*)m_pLoadArray); delete (CObject*)m_pLoadArray; m_pLoadArray = NULL;</b>Посмотрим, что происходит с архивом в случае прекращения работы посредством вызова метода AbortQ. Первым делом метод «отсоединяет» архив от файла, присваивая полю m__pFile значе­ние NULL. Затем в том случае, если у архива есть ассоциированный с ним буфер, производится удаление буфера. Если в буфере остались данные, которые не были записаны в файл, то эти данные будут потеряны. Указатели на начало буфера и на текущую позицию буфера делаются равными NULL. Затем удаляется указатель на хэш-таблицу, содержащую номера схем классов, а за ней и хэш-таблица (или массив) сохраненных объектов.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-abort-2.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ненулевое значение</title>
		<link>http://www.programmfc.ru/uncategorized/%d0%bd%d0%b5%d0%bd%d1%83%d0%bb%d0%b5%d0%b2%d0%be%d0%b5-%d0%b7%d0%bd%d0%b0%d1%87%d0%b5%d0%bd%d0%b8%d0%b5.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d0%bd%d0%b5%d0%bd%d1%83%d0%bb%d0%b5%d0%b2%d0%be%d0%b5-%d0%b7%d0%bd%d0%b0%d1%87%d0%b5%d0%bd%d0%b8%d0%b5.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:30:21 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Приложения]]></category>
		<category><![CDATA[Load]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d0%bd%d0%b5%d0%bd%d1%83%d0%bb%d0%b5%d0%b2%d0%be%d0%b5-%d0%b7%d0%bd%d0%b0%d1%87%d0%b5%d0%bd%d0%b8%d0%b5.html</guid>
		<description><![CDATA[Метод производит считывание номера схемы класса и длины названия класса без учета завершающего нулевого байта, после чего в выделенный для названия класса символьный массив чита­ет название класса. Если указанное в архиве число символов в на­звании класса превышает размер выделенного для него буфера или же при считывании из архива было считано меньше, чем ука­зано, байтов, то [...]]]></description>
			<content:encoded><![CDATA[<p>Метод производит считывание номера схемы класса и длины названия класса без учета завершающего нулевого байта, после чего в выделенный для названия класса символьный массив чита­ет название класса. Если указанное в архиве число символов в на­звании класса превышает размер выделенного для него буфера или же при считывании из архива было считано меньше, чем ука­зано, байтов, то метод немедленно возвращает NULL. После того как название класса считано, к нему дописывается нулевой байт, т. е. с этого момента название класса становится обычной строкой, завершающейся нулевым байтом. Затем метод проверяет, описан ли класс, название которого прочитано в архиве, в текущем про­цессе. Если класс не описан, то метод возвращает значение NULL. Таким образом, <i>если: а) длина имени сохраненного класса равна 64 байтам или больше; б) если при считывании имени класса произошла какая-то ошибка и было считано меньше символов, чем указано; в) класс не описан в вызывающем модуле, то метод CRuntime::Load() возвращает значение NULL. </i>Если же все про­верки прошли нормально, то возвращается указатель на инфор­мацию времени выполнения того класса, имя которого совпадает и именем считанного из архива класса, и управление опять пере­ходит в метод ReadClassQ. <i>Таким образом, если метод CRuntimeClass::Load() возвратил ненулевое значение, то это яв­ляется признаком того, что в процессе, осуществляющем чте­ние из архива, класс, описание которого только что было счи­тано из архива, также описан и процесс готов работать с объ­ектами данного класса.</i></p>
<p>Если метод CRuntimeClass::Load() вернул значение NULL, это означает, что произошла ошибка, которую метод ReadClass() са­мостоятельно устранить не в состоянии. Естественный выход для метода ReadClass() в этой ситуации &#8211; выработка исключения, что он и делает. Если же загрузка прошла нормально, то начинается проверка соответствия схем (версий) классов, ведь вполне веро­ятно, что в программе используется описание более новой версии класса, чем сохраненная в архиве, верно?</p>
<p>Если схемы класса в вызывающем модуле и в считанной из ар­хива информации не совпали и при этом не указано, что класс мо­жет загружать информацию разных версий, то вырабатывается ис­ключение. В том случае, если схемы не совпадают, но указано, что класс может загружать информацию разных версий, для хранения несовпадающих версий заводится новая хэш-таблица, указатель на нее записывается в поле mjDSchemaMap. Ключами в этой таб­лице служат указатели на информацию времени выполнения клас­са, считанного из архива, а значения, которые принимают элемен­ты, равны номерам схем считанных из архива классов. Здесь я не поленюсь лишний раз повторить, что хэш-таблица заводится для хранения ТОЛЬКО тех схем, номера которых НЕ СОВПАДАЮТ со схемой класса, информация о котором передана методу в качестве аргумента.</p>
<p>Раз заведена хэш-таблица, то как же обойтись без проверки числа элементов в ней при помощи метода CheckCount()? А после проверки указатель на информацию времени исполнения класса записывается в очередной свободный элемент массива указателей, который был заведен при вызове метода MapObject(). Естественно, число элемен­тов в этом массиве увеличивается на единицу. *</p>
<p>Тем самым мы завершили обработку описания впервые встре­тившегося класса. А что происходит в тех случаях, когда мы счи­тываем ссылки на ранее встречавшиеся описания классов? Если индекс ранее встречавшегося класса не равен нулю (если читатель помнит, то нулевой элемент массива инициализируется значением NULL) и не превышает верхнего индекса массива (индекс в таком случае просто лишен смысла), из элемента массива с указанным индексом выбирается информация времени исполнения класса&#8230;</p>
<p>Так&#8230; А почему мы постоянно говорим о массиве? Дело в том, что индекс, с которым элемент был добавлен в ХЭШ-ТАБЛИЦУ при записи в архив, может использоваться как индекс МАССИВА при считывании из архива. Ведь в данном случае нам не нужно осуществлять массу проверок, верно? И для хранения данных вполне достаточно массива, доступ к элементам которого можно осуществлять по индексам, верно?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d0%bd%d0%b5%d0%bd%d1%83%d0%bb%d0%b5%d0%b2%d0%be%d0%b5-%d0%b7%d0%bd%d0%b0%d1%87%d0%b5%d0%bd%d0%b8%d0%b5.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Метод CRuntimeClass::Load</title>
		<link>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-cruntimeclassload.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-cruntimeclassload.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:30:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Приложения]]></category>
		<category><![CDATA[Load]]></category>
		<category><![CDATA[Метод CRuntimeClass]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-cruntimeclassload.html</guid>
		<description><![CDATA[Практически сразу после вызова ReadClassQ вызывает ме­тод MapObject() с параметром NULL. Но обратите внимание, чи­татель, на то, что в случае чтения информации из архива соз­дается не хэш-таблица, а МАССИВ указателей. Указатель на массив записывается в поле m_pLoadArray, которое, кстати, опи­сано в одном объединении (union&#8217;e) с полем m_pStoreMap. После этого в архиве создается один элемент, в [...]]]></description>
			<content:encoded><![CDATA[<p>Практически сразу после вызова ReadClassQ вызывает ме­тод MapObject() с параметром NULL. Но обратите внимание, чи­татель, на то, что в случае чтения информации из архива соз­дается не хэш-таблица, а МАССИВ указателей. Указатель на массив записывается в поле m_pLoadArray, которое, кстати, опи­сано в одном объединении (union&#8217;e) с полем m_pStoreMap. После этого в архиве создается один элемент, в который записывается значение NULL. Естественно, счетчик элементов массива, т. е. значение поля m_nMapCount, тоже делается равным одному. Как и в случае сохранения информации в массиве, при аргументе, равном NULL метод больше ничего не делает. Таким образом, <i>вызов метода MapObject() с параметром NULL при чтении из архива приводит к созданию и инициализации массива указателей.</i></p>
<p>Затем метод ReadClass() начинает работу в точном соответствии с тем списком правил, который мы сформировали в конце предыду­щего раздела. <i>В том случае, если считан тэг объекта, то метод записывает тэг объекта по адресу, переданному ему в качестве третьего аргумента, и возвращает значение NULL. </i>Отметим этот факт &#8211; <i>метод ReadClassQ в том случае, если из архива считан тэг объекта, возвращает значение NULL. </i>У объекта схемы (версии) быть не может, поэтому мы не заполняем указатель на схему. Однако если из архива считан тэг класса, нам придется немного повозиться с этим тэгом.</p>
<p>Давайте рассуждать. Если встречен тэг класса, то какие случаи должны быть рассмотрены при этом? Наверное, должны быть рас­смотрены два случая: 1) считан тэг ранее не встречавшегося клас­са и 2) считана ссылка на тэг ранее встречавшегося в процессе считывания класса. В том случае, если метод ReadClass() считал из архива тэг ранее не встречавшегося класса, то он должен загрузить информацию времени выполнения этого класса, после чего осуществить все необходимые проверки, верно? Информация вре­мени выполнения загружается при помощи метода CRuntimeClass::Load(), исходный текст которого можно найти в файле агссоге.срр:</p>
<p><b>CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive&amp; ar,</b></p>
<p><b>UINT*&#8217;pwSchemaNum)</b></p>
<p><b>// loads a runtime class description</b></p>
<p><b>{</b></p>
<p><b>WORD nLen;</b></p>
<p><b>char szClassName[64]; CRuntimeClass* pClass;</b></p>
<p><b>WORD wTemp;</b></p>
<p><b>ar &gt;&gt; wTemp; *pwSchemaNum = wTemp; ar &gt;&gt; nLen;</b></p>
<p><b>if (nLen &gt;= _countof(szClassName) ||</b></p>
<p><b>ar.Read(szClassName, nLen*sizeof(char)) !=</b></p>
<p><b>nLen*sizeof(char))</b></p>
<p><b>{</b></p>
<p><b>return NULL;</b></p>
<p><b>}</b></p>
<p><b>szClassName[nLen] = </b><b><sup>Л</sup></b><b>\0&#8242;;</b></p>
<p><b>// search app specific classes</b></p>
<p><b>AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); AfxLockGlobals(CRIT_RUNTIMECLASSLIST);</b></p>
<p><b>for (pClass = pModuleState-&gt;m_classList; pClass != NULL; pClass = pClass-&gt;m_pNextClass)</b></p>
<p><b>{</b></p>
<p><b>if (IstrcmpA(szClassName,</b></p>
<p><b>pClass-&gt;m_lpszClassName) == 0)</b></p>
<p><b>{</b></p>
<p><b>AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST); return pClass;</b></p>
<p><b>}</b></p>
<p><b>}</b></p>
<p><b>AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);</b></p>
<p><b>#ifdef _AFXDLL</b></p>
<p><b>// search classes in shared DLLs AfxLockGlobals(CRITJDYNLINKLIST);</b></p>
<p><b>for (CDynLinkLibrary* pDLL = pModuleState-&gt;m_libraryList; pDLL != NULL; pDLL = pDLL-&gt;m_pNextDLL)</b></p>
<p><b>{</b></p>
<p><b>for (pClass = pDLL-&gt;m_classList; pClass != NULL; pClass = pClass-&gt;m_pNextClass)</b></p>
<p><b>{</b></p>
<p><b>if (IstrcmpA(szClassName,</b></p>
<p><b>pClass-&gt;m_lpszClassName) == 0)</b></p>
<p><b>{</b></p>
<p><b>AfxUnlockGlobals(CRIT_DYNLINKL1ST) ; return pClass;</b></p>
<p><b>}</b></p>
<p><b>}</b></p>
<p><b>}</b></p>
<p><b>AfxUnlockGlobals(CRIT_DYNLINKLIST); #endif</b></p>
<p><b>TRACE1 (&quot;&#8217;Warning: Cannot load %hs from archive.</b></p>
<p><b>Class not defined.\n&quot;, szClassName);</b></p>
<p><b>return NULL; // not found</b></p>
<p><b>}</b></p>
<p>В тексте этого метода нужно обратить внимание на одну ме­лочь: для чтения названия класса выделяется буфер размером 64 байта. Следовательно, название класса не может быть длин­нее 64 символов.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-cruntimeclassload.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Чтение объектов из архива</title>
		<link>http://www.programmfc.ru/uncategorized/%d1%87%d1%82%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%be%d0%b2-%d0%b8%d0%b7-%d0%b0%d1%80%d1%85%d0%b8%d0%b2%d0%b0.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d1%87%d1%82%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%be%d0%b2-%d0%b8%d0%b7-%d0%b0%d1%80%d1%85%d0%b8%d0%b2%d0%b0.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:29:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Приложения]]></category>
		<category><![CDATA[Load]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d1%87%d1%82%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%be%d0%b2-%d0%b8%d0%b7-%d0%b0%d1%80%d1%85%d0%b8%d0%b2%d0%b0.html</guid>
		<description><![CDATA[Уважаемый читатель, я очень надеюсь, что вы не пожалели време­ни, затраченного на изучение процесса записи объектов в архив. Несмотря на то, что вы, зная формат архива, в состоянии само­стоятельно считать данные из архива, нам необходимо довести дело до логического завершения и изучить, каким образом объек­ты, сохраненные в архиве, могут быть извлечены оттуда средства­ми библиотеки MFC. [...]]]></description>
			<content:encoded><![CDATA[<p>Уважаемый читатель, я очень надеюсь, что вы не пожалели време­ни, затраченного на изучение процесса записи объектов в архив. Несмотря на то, что вы, зная формат архива, в состоянии само­стоятельно считать данные из архива, нам необходимо довести дело до логического завершения и изучить, каким образом объек­ты, сохраненные в архиве, могут быть извлечены оттуда средства­ми библиотеки MFC. Для того чтобы осуществить чтение объекта из архива, можно воспользоваться методом ReadObject(), который в файле arcobj.cpp описан следующим образом:</p>
<p><b>CObject* CArchive::ReadObject(const CRuntimeClass*</b></p>
<p><b>pClassRefRequested)</b></p>
<p><b>{</b></p>
<p><b>ASSERT(pClassRefRequested == NULL || AfxIsValidAddress(pClassRefRequested,</b></p>
<p><b>sizeof(CRuntimeClass), FALSE));</b></p>
<p><b>ASSERT(IsLoading()); // proper direction ASSERT(wNullTag == 0);</b></p>
<p><b>ASSERT((wClassTag « 16) == dwBigClassTag); ASSERT((wNewClassTag &amp; wClassTag) == wClassTag);</b></p>
<p><b>// attempt to load next stream as CRuntimeClass UINT nSchema; DWORD obTag;</b></p>
<p><b>CRuntimeClass* pClassRef = ReadClass(pClassRefRequested,</b></p>
<p><b>SnSchema, &amp;obTag);</b></p>
<p><b>// check to see if tag to already loaded object CObject* pOb; if (pClassRef == NULL) {</b></p>
<p><b>if (obTag &gt; (DWORD)m_pLoadArray-&gt;GetUpperBound()) {</b></p>
<p><b>// tag is too large for the number of objects read so far AfxThrowArchiveException(CArchiveException::badlndex,</b></p>
<p><b>m_strFileName);</b></p>
<p><b>}</b></p>
<p><b>pOb = (CObject*)m_pLoadArray-&gt;GetAt(obTag); if (pOb != NULL &amp;&amp;</b></p>
<p><b>pClassRefRequested != NULL &amp;&amp; !pOb-&gt;IsKindOf(pClassRefRequested))</b></p>
<p>{</p>
<p><b>// loaded an object but of the wrong class</b></p>
<p><b>AfxThrowArchiveException(CArchiveException:rbadClass,</b></p>
<p><b>m_strFileName);</b></p>
<p><b>}</b></p>
<p><b>}</b></p>
<p><b>else {</b></p>
<p><b>// allocate a new object based on the class just acquired pOb = pClassRef-&gt;CreateObject(); if (pOb == NULL)</b></p>
<p><b>AfxThrowMemoryException();</b></p>
<p><b>// Add to mapping array BEFORE de-serializing CheckCount();</b></p>
<p><b>m_pLoadArray-&gt;InsertAt(m_nMapCount + + , pOb) ;</b></p>
<p><b>// Serialize the object with the schema number set // in the archive</b></p>
<p><b>UINT nSchemaSave = m_nObjectSchema;</b></p>
<p><b>m_nObjectSchema = nSchema;</b></p>
<p><b>pOb-&gt;Serialize(*this);</b></p>
<p><b>m_nObjectSchema = nSchemaSave;</b></p>
<p><b>ASSERT_VALID(pOb) ;</b></p>
<p><b>}</b></p>
<p><b>return pOb;</b></p>
<p>}</p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d1%87%d1%82%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%be%d0%b2-%d0%b8%d0%b7-%d0%b0%d1%80%d1%85%d0%b8%d0%b2%d0%b0.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Метод MapObject</title>
		<link>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-mapobject.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-mapobject.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:25:50 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Приложения]]></category>
		<category><![CDATA[Работа с файлами]]></category>
		<category><![CDATA[Load]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-mapobject.html</guid>
		<description><![CDATA[Что ж, в связи с важностью метода необходимо этот метод рассмотреть более подробно. Понятно, что в качестве аргумен­та методу передается указатель на записываемый в архив объ­ект. Сразу после проведения необходимых проверок вызывает­ся метод MapObject(). При этом (обратите, пожалуйста, на это внимание, читатель) методу MapObject() в качестве аргумента передается не указатель на объект, как следовало бы [...]]]></description>
			<content:encoded><![CDATA[<p>Что ж, в связи с важностью метода необходимо этот метод рассмотреть более подробно. Понятно, что в качестве аргумен­та методу передается указатель на записываемый в архив объ­ект. Сразу после проведения необходимых проверок вызывает­ся метод MapObject(). При этом (обратите, пожалуйста, на это внимание, читатель) методу MapObject() в качестве аргумента передается не указатель на объект, как следовало бы ожидать, a NULL. Исходный код метода MapObject() также находится в фай­ле arcobj.cpp:</p>
<p><b>void CArchive::MapObject(const CObject* pOb) {</b></p>
<p><b>if (IsStoring()) {</b></p>
<p><b>if (m_pStoreMap == NULL) {</b></p>
<p><b>// initialize the storage map</b></p>
<p><b>// (use CMapPtrToPtr because it is used for</b></p>
<p><b>// HANDLE maps too)</b></p>
<p><b>m_pStoreMap = new CMapPtrToPtr(m_nGrowSize) ; m_pStoreMap-&gt;InitHashTable(m_nHashSize); m_pStoreMap-&gt;SetAt(NULL, (void*) (DWORD)wNullTag) ; m_nMapCount = 1;</b></p>
<p>}</p>
<p><b>if (pOb != NULL) {</b></p>
<p><b>CheckCount(); (*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;</b></p>
<p><b><i>}</i></b></p>
<p>}</p>
<p><b>else {</b></p>
<p><b>if (m_pLoadArray == NULL) {</b></p>
<p><b>// initialize the loaded object pointer array // and set special values m_pLoadArray = new CPtrArray; m_pLoadArray-&gt;SetSize(1, m_nGrowSize); ASSERT(wNullTag == 0); m_pLoadArray-&gt;SetAt(wNullTag, NULL); m_nMapCount = 1;</b></p>
<p><b>}</b></p>
<p><b>if (pOb != NULL) {</b></p>
<p><b>CheckCount() ;</b></p>
<p><b>m_pLoadArray-&gt;InsertAt(m_nMapCount++, (void*)pOb);</b></p>
<p><b>}</b></p>
<p><b>}</b></p>
<p>}</p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-mapobject.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Код оператора</title>
		<link>http://www.programmfc.ru/uncategorized/%d0%ba%d0%be%d0%b4-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%be%d1%80%d0%b0.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d0%ba%d0%be%d0%b4-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%be%d1%80%d0%b0.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:24:13 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Приложения]]></category>
		<category><![CDATA[Работа с файлами]]></category>
		<category><![CDATA[Load]]></category>
		<category><![CDATA[Код оператора]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d0%ba%d0%be%d0%b4-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%be%d1%80%d0%b0.html</guid>
		<description><![CDATA[Теперь мы знаем, как осуществляется чтение из архива про­стых типов данных. Надеюсь, для того чтобы разобрать перегру­женный оператор ««», нам потребуется значительно меньше вре­мени. Код оператора также существует в двух вариантах, опять мы остановимся на более простом, который находится в файле afx.h:
Схема взаимоотношения буфера и его полей
_AFX_INLINE CArchive&#38; CArchive::operator«(WORD w) {
if (m_lpBufCur + sizeof(WORD) &#62; [...]]]></description>
			<content:encoded><![CDATA[<p>Теперь мы знаем, как осуществляется чтение из архива про­стых типов данных. Надеюсь, для того чтобы разобрать перегру­женный оператор ««», нам потребуется значительно меньше вре­мени. Код оператора также существует в двух вариантах, опять мы остановимся на более простом, который находится в файле afx.h:</p>
<p><b>Схема взаимоотношения буфера и его полей</b></p>
<p><b>_AFX_INLINE CArchive&amp; CArchive::operator«(WORD w) {</b></p>
<p><b>if (m_lpBufCur + sizeof(WORD) &gt; m_lpBufMax) Flush();</b></p>
<p><b>*(UNALIGNED WORD*)m_lpBufCur = w; m_lpBufCur += sizeof(WORD); return *this;</b></p>
<p><b>}</b></p>
<p>Так&#8230; В том случае, если для записи в буфер не хватает места, то вызывается метод Flush(), исходный код которого находится в файле агссоге.срр и тоже достаточно велик:</p>
<p><b>void CArchive::Flush() {</b></p>
<p><b>ASSERT_VALID(m_pFile);</b></p>
<p><b>ASSERT(m_bDirectBuffer || m_lpBufStart !=NULL); ASSERT(m_bDirectBuffer || m_lpBufCur !=NULL); ASSERT(m_lpBufStart == NULL ||</b></p>
<p><b>AfxIsValidAddress(m_lpBufStart,</b></p>
<p><b>m_lpBufMax &#8211; m_lpBufStart,</b></p>
<p><b>IsStoring ())); ASSERT(m_lpBufCur == NULL ||</b></p>
<p><b>AfxIsValidAddress(m_lpBufCur,</b></p>
<p><b>m_lpBufMax &#8211; m_lpBufCur,</b></p>
<p><b>IsStoring ()));</b></p>
<p><b>if (IsLoading()) {</b></p>
<p><b>// unget the characters in the buffer, // seek back unused amount</b></p>
<p><b>if (m_lpBufMax != m_lpBufCur)</b></p>
<p><b>m_pFile-&gt;Seek(-(m_lpBufMax &#8211; m_lpBufCur), CFile::current); m_lpBufCur = mjlpBufMax; // empty</b></p>
<p>}</p>
<p><b>else {</b></p>
<p><b>if (!m_bDirectBuffer) {</b></p>
<p><b>// write out the current buffer to file if (m_lpBufCur != m_lpBufStart) m_pFile-&gt;Write(m_lpBufStart, m_lpBufCur &#8211; m_lpBufStart);</b></p>
<p><b>}</b></p>
<p><b>else {</b></p>
<p><b>// commit current buffer</b></p>
<p><b>if (m_lpBufCur != m_lpBufStart)</b></p>
<p><b>m_pFile-&gt;GetBufferPtr(CFile::bufferCommit,</b></p>
<p><b>m_lpBufCur &#8211; m_lpBufStart) ;</b></p>
<p><b>// get next buffer</b> <b>«.</b></p>
<p><b>VERIFY(m_pFile-&gt;GetBufferPtr(CFile::bufferWrite,</b></p>
<p><b>m_nBufSize, (void**)&amp;m_lpBufStart, (void**)&amp;m_lpBufMax) == (UINT)m_nBufSize) ; ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax -</b></p>
<p><b>m_lpBufStart)) ;</b></p>
<p><b>}</b></p>
<p><b>m_lpBufCur = m_lpBufStart;</b></p>
<p><b>}</b></p>
<p><b>}</b></p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d0%ba%d0%be%d0%b4-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%82%d0%be%d1%80%d0%b0.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Метод FillBuffer</title>
		<link>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-fillbuffer.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-fillbuffer.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:23:36 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Приложения]]></category>
		<category><![CDATA[Работа с файлами]]></category>
		<category><![CDATA[Load]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-fillbuffer.html</guid>
		<description><![CDATA[Первым делом оператор проверяет, хватит ли распределенной под буфер памяти для того, чтобы записать еще одно слово. Если памяти не хватает, то вызывается метод FillBuffer(), которому в качестве аргу­мента передается количество байтов, недостаточных для нормаль­ного выполнения операции записи. Исходный код метода FillBuffer() можно найти в файле агссоге.срр. Я прошу читателя запастись терпе­нием, потому что код [...]]]></description>
			<content:encoded><![CDATA[<p>Первым делом оператор проверяет, хватит ли распределенной под буфер памяти для того, чтобы записать еще одно слово. Если памяти не хватает, то вызывается метод FillBuffer(), которому в качестве аргу­мента передается количество байтов, недостаточных для нормаль­ного выполнения операции записи. Исходный код метода FillBuffer() можно найти в файле агссоге.срр. Я прошу читателя запастись терпе­нием, потому что код метода достаточно объемен:</p>
<p><b>void CArchive::FillBuffer(UINT nBytesNeeded) {</b></p>
<p><b>ASSERT_VALID(m_pFile); ASSERT (IsLoadingO ) ;</b></p>
<p><b>ASSERT(m_bDirectBuffer || m_lpBufStart !=NULL); ASSERT(m_bDirectBuffer || m_lpBufCur !=NULL); ASSERT(nBytesNeeded &gt; 0);</b></p>
<p><b>ASSERT(nBytesNeeded &lt;= (UINT)m_nBufSize); ASSERT(m_lpBufStart == NULL ||</b></p>
<p><b>AfxIsValidAddress(m_lpBufStart,</b></p>
<p><b>m_lpBufMax &#8211; m_lpBufStart, FALSE)); ASSERT(m_lpBufCur == NULL ||</b></p>
<p><b>AfxIsValidAddress(m_lpBufCur,</b></p>
<p><b>m_lpBufMax &#8211; m_lpBufCur, FALSE));</b></p>
<p><b>UINT nUnused = m_lpBufMax &#8211; m_lpBufCur;</b></p>
<p><b>ULONG nTotalNeeded = ( (ULONG)nBytesNeeded) + nUnused;</b></p>
<p><b>// fill up the current buffer from file if (!m_bDirectBuffer) {</b></p>
<p><b>ASSERT(m_lpBufCur != NULL); ASSERT(m_lpBufStart != NULL); ASSERT(m_lpBufMax !=NULL);</b></p>
<p><b>if (m_lpBufCur &gt; m_lpBufStart) {</b></p>
<p><b>// copy unused</b></p>
<p><b>if ( (int)nUnused &gt; 0) {</b></p>
<p><b>memmove(m_lpBufStart, m_lpBufCur, nUnused); m_lpBufCur = m_lpBufStart; m_lpBufMax = m_lpBufStart + nUnused;</b></p>
<p>}</p>
<p><b>// read to satisfy nBytesNeeded or nLeft if possible UINT nRead = nUnused; UINT nLeft = m_nBufSize-nUnused; UINT nBytes;</b></p>
<p><b>BYTE* lpTemp = m_lpBufStart + nUnused;</b></p>
<p><b>do</b></p>
<p><b>{</b></p>
<p><b>nBytes = m_pFile-&gt;Read(lpTemp, nLeft); lpTemp = lpTemp + nBytes; nRead += nBytes; nLeft -= nBytes;</b></p>
<p>}</p>
<p><b>while (nBytes &gt; 0 &amp;&amp; nLeft &gt; 0 &amp;&amp; nRead &lt; nBytesNeeded);</b></p>
<p><b>m_lpBufCur = m_lpBufStart; m_lpBufMax = m_lpBufStart + nRead;</b></p>
<p><b>}</b></p>
<p><b>}</b></p>
<p><b>else {</b></p>
<p><b>// seek to unused portion and get the buffer</b></p>
<p><i>I/ </i><b>starting there if (nUnused != 0)</b></p>
<p><b>m_pFile-&gt;Seek(-(LONG)nUnused, CFile::current); UINT nActual = m_pFile-&gt;GetBufferPtr(CFile::bufferRead,</b></p>
<p><b>m_nBufSize, (void**)&amp;m_lpBufStart, (void**)&amp;m_lpBufMax) ; ASSERT(nActual == (UINT)(m_lpBufMax &#8211; m_lpBufStart)); m_lpBufCur = m_lpBufStart;</b></p>
<p><b>}</b></p>
<p><b>// not enough data to fill request?</b></p>
<p><b>if ( (ULONG) (m_lpBufMax &#8211; m_lpBufCur) &lt; nTotalNeeded) AfxThrowArchiveException(CArchiveException::endOfFile);</b></p>
<p><b>}</b></p>
<p>После проверки и, при необходимости, выдачи всех предупреж­дений метод определяет прежде всего число неиспользуемых бай­тов в буфере. Обратите внимание на то, что это значение вычис­ляется как разность между значениями полей mJpBufMax и mJpBufCur, а не (mJpBufStart + m_nBufSize &#8211; mJpBufCur). Почему? Пока непонятно&#8230; Затем определяется, сколько всего бай­тов необходимо для того, чтобы операция чтения могла завер­шиться нормально. Естественно, число необходимых байтов равно сумме числа неиспользуемых байтов в буфере и числа недоста­ющих байтов, переданных методу в качестве аргумента. Далее про­исходит следующее. Если у нас буфер занят частично, т. е. число неиспользуемых байтов не равно нулю, то мы копируем свободный участок памяти в начало буфера. При этом указатель на текущую позицию в буфере устанавливается на начало буфера. Это понятно. Но непонятно следующее &#8211; почему указатель m JpBufMax устанав­ливается на конец переписанного участка? Подождите, пожалуйста, осталось совсем недолго&#8230;</p>
<p>Идем дальше. И вот здесь&#8230; Посмотрите: значение переменной nRead делается равным числу неиспользованных байтов! Опять за­гадка. .. Определяем, сколько байтов еще необходимо считать для того, чтобы заполнить буфер до конца, читаем из файла в буфер&#8230; Полю mJpBufCur присваиваивается значение указателя на начало буфера&#8230; Вот оно! В поле mJpBufMax мы записываем число считан­ных байтов! Т. е. поле mJpBufMax указывает на конец тех данных, которые мы считали! Обычно поле mJpBufMax будет указывать на считывании достигли конца файла! В этом случае поле mJpBufMax будет указывать куда-то на середину буфера, на последний байт считанных данных! Т. е. поле mJpBufMax указывает на конец считанных данных!</p>
<p>Понятно теперь, почему неиспользованным участком считается участок от указателя на текущую позицию в буфере до указателя mJpBufMax. Конечно же! Ведь после предыдущих операций чтения мы могли выполнять операции записи, т. е. указатель на текущую позицию в файле мог сместиться в сторону уменьшения. Но ведь в этом участке находятся данные, которые мы уже считывали! Зачем нам осуществлять считывание одних и тех же данных повторно? Естественно, нам легче их скопировать из одного места буфера в другое, чем осуществлять лишние обращения к диску!</p>
<p>Схематично взаимоотношения буфера и его полей показаны на 9.</p>
<p>Подводя итог сказанному выше, можно сделать вывод о том, что <i>метод FHIBufferQ осуществляет заполнение выделенного ар­хиву буфера данными из файла, осуществляя буферированное чтение данных.</i></p>
<p>Обратите внимание, что указатель m JpBufCur после осуществ­ления считывания данных указывает на начало буфера. А теперь, если мы вернемся в код перегруженного оператора «»», мы уви­дим, что сразу после вызова FillBuffer() оператор записывает по указанной ему ссылке считанное слово и увеличивает указатель mJpBufCur на величину, равную размеру считанного данного. Ука­затель mJpBufCur занимает то положение, которое и должен за­нимать!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d0%bc%d0%b5%d1%82%d0%be%d0%b4-fillbuffer.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Шаг 6</title>
		<link>http://www.programmfc.ru/arxitektura/%d1%88%d0%b0%d0%b3-6.html</link>
		<comments>http://www.programmfc.ru/arxitektura/%d1%88%d0%b0%d0%b3-6.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:08:30 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Архитектура]]></category>
		<category><![CDATA[Load]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d1%88%d0%b0%d0%b3-6.html</guid>
		<description><![CDATA[// Шаг 6. Регистрируем класс окон, к которому будет // принадлежать главное окно приложения.
pszWndClassName = AfxRegisterWndClass ( CS_HREDRAW &#124;
CS_VREDRAW, LoadStandardCursor( IDC_ARROW ), ( HBRUSH ) ::GetStockObject( WHITE_BRUSH ), LoadStandardlcon( IDI_APPLICATION ) );
]]></description>
			<content:encoded><![CDATA[<p>// Шаг 6. Регистрируем класс окон, к которому будет // принадлежать главное окно приложения.</p>
<p>pszWndClassName = AfxRegisterWndClass ( CS_HREDRAW |</p>
<p>CS_VREDRAW, LoadStandardCursor( IDC_ARROW ), ( HBRUSH ) ::GetStockObject( WHITE_BRUSH ), LoadStandardlcon( IDI_APPLICATION ) );</p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/arxitektura/%d1%88%d0%b0%d0%b3-6.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Информация времени выполнения</title>
		<link>http://www.programmfc.ru/uncategorized/%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2%d1%8b%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d1%8f.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2%d1%8b%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d1%8f.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:04:07 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Load]]></category>
		<category><![CDATA[Информация времени выполнения]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2%d1%8b%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d1%8f.html</guid>
		<description><![CDATA[Однако я не могу считать раскрытой до конца тему о написании программ для MFC. Дело в том, что в исходных кодах MFC на каж­дом шагу попадаются макросы с именами DECLARE_DYNAMIC(), IMPLEMENTJDYNAMfCO, DECLARE_DYNCREATE() и IMPLEMENT-_DYNCREATE(). О них-то мы сейчас и поговорим.
У каждого объекта, унаследованного от объекта класса СОЬ-ject, есть поле, содержащее в себе информацию времени выпол­нения. [...]]]></description>
			<content:encoded><![CDATA[<p>Однако я не могу считать раскрытой до конца тему о написании программ для MFC. Дело в том, что в исходных кодах MFC на каж­дом шагу попадаются макросы с именами DECLARE_DYNAMIC(), IMPLEMENTJDYNAMfCO, DECLARE_DYNCREATE() и IMPLEMENT-_DYNCREATE(). О них-то мы сейчас и поговорим.</p>
<p>У каждого объекта, унаследованного от объекта класса СОЬ-ject, есть поле, содержащее в себе информацию времени выпол­нения. Эта информация представляет собой структуру типа CRunt-imeClass, которая описана в файле следующим образом:</p>
<p><b>struct CRuntimeClass {</b></p>
<p><b>// Attributes</b></p>
<p><b>LPCSTR m_lpszClassName; int m_nObjectSize;</b></p>
<p><b>UINT m_wSchema; // schema number of the loaded class CObject* (PASCAL* m_pfnCreateObject) () ;</b></p>
<p><b>// NULL =&gt; abstract class</b></p>
<p><b>#ifdef _AFXDLL</b></p>
<p><b>CRuntimeClass* (PASCAL* m_pfnGetBaseClass) (); #else</b></p>
<p><b>CRuntimeClass* m_pBaseClass; #endif</b></p>
<p><b>// Operations</b></p>
<p><b>CObject* CreateObject();</b></p>
<p><b>BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;</b></p>
<p><b>// Implementation</b></p>
<p><b>void Store(CArchive&amp; ar) const;</b></p>
<p><b>static CRuntimeClass* PASCAL Load(CArchive&amp; ar,</b></p>
<p><b>UINT* pwSchemaNum) ; // CRuntimeClass objects linked together in simple list CRuntimeClass* m_pNextClass;</b></p>
<p><b>// linked list of registered classes</b></p>
<p><b>};</b></p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2%d1%8b%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d1%8f.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Что хранит в себе информация времени выполнения?</title>
		<link>http://www.programmfc.ru/uncategorized/%d1%87%d1%82%d0%be-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d1%82-%d0%b2-%d1%81%d0%b5%d0%b1%d0%b5-%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2.html</link>
		<comments>http://www.programmfc.ru/uncategorized/%d1%87%d1%82%d0%be-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d1%82-%d0%b2-%d1%81%d0%b5%d0%b1%d0%b5-%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 19:04:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Первая программа на MFC]]></category>
		<category><![CDATA[Load]]></category>

		<guid isPermaLink="false">http://www.programmfc.ru/uncategorized/%d1%87%d1%82%d0%be-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d1%82-%d0%b2-%d1%81%d0%b5%d0%b1%d0%b5-%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2.html</guid>
		<description><![CDATA[Что хранит в себе информация времени выполнения? Есте­ственно, она должна хранить имя класса. Для хранения имени класса служит поле mJpszClassName. Для того чтобы мы могли создать объект этого класса динамически, мы должны знать раз­мер, который занимает объект этого класса. Размер объекта хра­нится в поле m__nObjectSize. Поле m__wSchema фактически яв­ляется номером версии класса. Дело в том, [...]]]></description>
			<content:encoded><![CDATA[<p>Что хранит в себе информация времени выполнения? Есте­ственно, она должна хранить имя класса. Для хранения имени класса служит поле mJpszClassName. Для того чтобы мы могли создать объект этого класса динамически, мы должны знать раз­мер, который занимает объект этого класса. Размер объекта хра­нится в поле m__nObjectSize. Поле m__wSchema фактически яв­ляется номером версии класса. Дело в том, что описание клас­са может изменяться от версии программы к версии, поэтому иногда (в частности, в ходе процесса сериализации) возникает необходимость узнать, к какой версии описания класса принад­лежит объект.</p>
<p>Для того чтобы в ходе выполнения программы мог быть создан объект класса, который описывает CRuntimeClass, она хранит в себе указатель на конструктор по умолчанию этого класса &#8211; поле m_pfnCreateObject (CObject* (PASCAL* m_pfnCreateObject)()). Не­посредственно для создания объекта можно воспользоваться ме­тодом CreateObjectQ, который, выполняя функцию, указатель на которую находится в поле m_pfnCreateObject, возвращает указатель на созданный объект.</p>
<p>Если в программе возникла необходимость получить информацию о том классе, от которого был унаследован описыва­емый в структуре файл, то для этого можно воспользоваться полем mjDfnGetBaseClass (CRuntimeClass* (PASCAL* m_pfnGetBase-Class)()), в котором находится указатель на метод, позволяющий получить такую информацию.</p>
<p>Для сохранения объекта описываемого класса в архиве служит метод Store(). Восстановить объект из архива можно при помощи метода Load(). О том, как работают эти методы, мы поговорим при рассмотрении процесса сериализации.</p>
<p>Но, наверное, самым интересным полем является поле mjDNextClass. Судя по тому, что оно фактически является указате­лем на информацию времени исполнения, а также взглянув на на­звание этого поля, можно догадаться, что все структуры типа CRuntimeClass объединены в однонаправленный список. Зная ука­затель на начало этого списка, мы можем получить информацию о том, какие классы зарегистрированы в системе.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.programmfc.ru/uncategorized/%d1%87%d1%82%d0%be-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d1%82-%d0%b2-%d1%81%d0%b5%d0%b1%d0%b5-%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
