<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:yandex="http://news.yandex.ru" xmlns:media="http://search.yahoo.com/mrss/" xmlns:turbo="http://turbo.yandex.ru">
	<channel>
		<title>Visual FoxPro Club</title>
		<link>https://foxclub.ru</link>
		<description>Visual FoxPro Club</description>
		<language>ru</language>
		<turbo:cms_plugin>7391CC2B1408947EFD5084459F5BD0CA</turbo:cms_plugin>
																	<item turbo="true">
					<link>https://foxclub.ru/faqs/mozhno-li-ukazat-massiv-v-kachestve-istochnika-dlya-grid/</link>
					<title><![CDATA[Можно ли указать массив в качестве источника для Grid]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Wed, 30 Nov 2022 05:19:42 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Можно ли указать массив в качестве источника для Grid</h1>
													</header>
													
<p></p>



<blockquote><b>Вопрос<br /></b>Можно ли в качестве источника данных для Grid указать массив?</blockquote>
<br /><br /><b>Ответ</b><br /><br />Нет. Напрямую это невозможно. Источником данных для Grid может быть только и исключительно таблица (курсор и View - это временные таблицы)<br /><br />Однако можно, используя команду CREATE CURSOR, создать временную таблицу и при помощи одной из команд<br />
<div class="foxcode">
<pre class="bbcode">APPEND FROM ARRAY ...<br />***или<br />INSERT INTO ... FROM ARRAY ...</pre>
<i class="num"></i></div>
<br />Наполнить эту временную таблицу данными из массива. Затем указать эту временную таблицу в качестве источника для Grid.
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/mozhno-li-ukazat-massiv-v-kachestve-istochnika-dlya-grid/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Grid]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-vydelit-vsyu-aktivnuyu-stroku-grid/</link>
					<title><![CDATA[Как выделить всю активную строку Grid]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Wed, 30 Nov 2022 05:12:33 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как выделить всю активную строку Grid</h1>
													</header>
													
<blockquote><b>Вопрос<br /></b>При перемещении по Grid выделяется только активная ячейка. Как выделить цветом все ячейки активной строки Grid ?</blockquote>
<br /><br /><b>Ответ</b><br /><br /><u><i>Для версии до Visual FoxPro 7 включительно.</i></u><br />
<ol>
<li>Необходимо создать дополнительное свойство формы ThisForm.nRecno. Можно сделать собственный класс Grid и создать этой свойство у собственно класса. И присвоить этому свойству числовое значение, например nRecno=1<br /><br />Новое свойство можно добавить через пункт меню Form (для класса Class), подпункт New Property или Edit Property/Method.<br /><br /></li>
<li>В событии Grid.Init пишем следующий код</li>
</ol>



<pre class="wp-block-code"><code>IF RECNO(This.RecordSource)#0 
    THIS.SetAll("DynamicBackColor",;
        "IIF(RECNO(This.RecordSource)=ThisForm.nRecno,RGB(255,255,0),RGB(255,255,255))",;
        "COLUMN") 
ENDIF</code></pre>



<p>Если свойство nRecno создано непосредственно в классе Grid, то, разумеется, следует вместо <em>ThisForm.nRecno</em> писать<em> This.nRecno</em></p>



<p>3. В событии Grid.AfterRowColChange пишем следующий код</p>



<p></p>



<pre class="wp-block-code"><code>LPARAMETERS nColIndex
ThisForm.nRecno = RECNO(This.RecordSource) 
This.Refresh()
***Если свойство nRecno создано непосредственно в классе Grid, то, разумеется, следует вместо ThisForm.nRecno писать This.nRecno</code></pre>



Все. Запускайте и пользуйтесь.<br /><br /><b>Замечание</b><br /><br />Если в качестве источника данных для Grid используется НЕ алиас, т.е. Grid.RecordSourceType&lt;&gt;1 - Alias, то необходимо ввести еще одно свойство, которое будет содержать имя алиаса из которого следует считывать значение Recno(). Или же просто явно прописывать имя алиаса непосредственно в коде.<br /><br /><br /><br /><u><i>Для версии от Visual FoxPro 8 и выше.</i></u><br /><br />Начиная с версии Visual FoxPro 8 ничего из приведенного выше писать не надо. Достаточно воспользоваться новыми свойствами Grid.<br /><br /><code><em>ThisForm.Grid.HighlightStyle = 2</em></code><br /><br />Если полученный цвет Вас не устраивает, то используйте свойства<br /><br /><code>ThisForm.Grid.HighlightBackColor - цвет фона</code><br /><code>ThisForm.Grid.HighlightForeColor - цвет шрифта</code><br /><br />В принципе, того же эффекта можно добиться, используя другое свойство<br /><br /><code>ThisForm.Grid.AllowCellSelection = .F.</code><br /><br />Однако следует понимать, что если свойство HighlightStyle отвечает только за способ (стиль) выделения цветом, то свойство AllowCellSelection отвечает также и за возможность выбора отдельной ячейки.<br /><br /><b>Замечание</b><br /><br />Если какая-либо колонка Grid имеет свойство Sparce = .F., то на нее не распространяется выделение цветом всей строки. В этом случае придется использовать старый способ для версий до Visual FoxPro 7 включительно, описанный выше.
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-vydelit-vsyu-aktivnuyu-stroku-grid/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Grid]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pochemu-nastrojki-yachejki-vidny-tolko-v-aktivnoj-yachejke/</link>
					<title><![CDATA[Почему настройки ячейки видны только в активной ячейке]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Wed, 30 Nov 2022 05:01:46 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Почему настройки ячейки видны только в активной ячейке</h1>
													</header>
													
<blockquote><b>Вопрос<br /></b>Я сделал настройки ячейки Grid (объекта Text1 в столбце): формат, выравнивание, отображение NULL и т.п. Однако эти настройки действуют только на текущую (активную) ячейку Grid. Как мне распространить действие этих настроек на все ячейки того же столбца?<br /><br />Я вставили в Grid вместо стандартного объекта Text1 какой-либо свой объект (например, ComboBox или свой TextBox). Однако мой объект виден только в текущей (активной) ячейке Grid. Как мне заставить отобразиться мой объект во всех ячейках того же столбца?</blockquote>
<br /><br /><b>Ответ</b><br /><br />Необходимо сделать для соответствующего столбца настройку<br />



<pre class="wp-block-code"><code>ThisForm.Grid1.Column1.Sparce = .F.</code></pre>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pochemu-nastrojki-yachejki-vidny-tolko-v-aktivnoj-yachejke/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Grid]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kto-v-dannyj-moment-rabotaet-s-prilozheniem/</link>
					<title><![CDATA[Кто в данный момент работает с приложением]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Tue, 29 Nov 2022 06:51:13 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Кто в данный момент работает с приложением</h1>
													</header>
													
<blockquote><b>Вопрос:<br /></b>Кто в данный момент работает с приложением</blockquote>
<br /><br /><b>Ответ:</b><br /><br />Чтобы ответить на этот вопрос необходимо вести учет всем "подключениям" к Вашему приложению. Т.е. некий лог всех подключений.<br /><br />С точки зрения FoxPro наиболее естественно хранить все данные о подключениях в таблице DBF. Однако просто делать запись в этой таблице в момент входа в приложение и удалять или очищать запись при выходе из приложения недостаточно. Дело в том, что выход из приложения может быть и аварийным. Т.е. результатом, например, сбоя питания или некорректных действий пользователя. Как следствие, запись в таблице есть, но реально пользователь с приложением не работает.<br /><br />Однако в среде FoxPro есть механизм взаимодействия нескольких пользователей одного приложения. Это блокировки. Ведь запись, заблокированную одним пользователем невозможно изменить другим пользователем, хотя можно прочитать из нее информацию. А в случае аварийного прерывания процесса блокировки будут сняты автоматически.<br /><br />Это значит, что если создать специальную таблицу, включенную в базу данных, записи которой будут содержать информацию о факте запуска приложения, то, наложив блокировку на соответствующую запись, можно дать знать другим экземплярам приложения кто уже работает с приложением.<br /><br />Чтобы операции с этой служебной таблицей не мешали основной работе приложения, лучше открывать ее в отдельной сессии данных. Это можно сделать, например, используя объект Session, введенный в Visual FoxPro 6.0 Service Pack 3. Для младших версий FoxPro придется очень аккуратно следить за установкой и снятием блокировок с таблиц. Т.е. за командами UNLOCK, RLOCK(), LOCK(), SET MULTILOCK. Хотя, можно использовать невидимую форму.<br /><br />Итак, в базе данных создается еще одна таблица. Это обычная таблица, принадлежащая базе данных. Т.е. таблица, лежащая на сервере, а не на локальном компьютере пользователя.<br /><br />Список полей этой таблицы является набором идентификаторов, по которым в Вашей задаче надо отделять процессы друг от друга. Это может быть, например:<br /><br />
<ul>
<li>SYS(0) – Идентификатор компьютера и логин пользователя при входе в Windows</li>
<li>Логин пользователя при входе в Ваше приложение</li>
<li>Дата и время последнего входа в Ваше приложение</li>
<li>GetEnv("SessionName") – имя сессии, в которой запущено приложение.<br /><br />
<blockquote class="bbcode"><strong>Замечание:</strong><br />Функция GetEnv() возвращает значение переменной созданной операционной системой. Полный список таких переменных и их значение можно посмотреть из режима командной строки Windows. Нажмите кнопку "Пуск" и выберите пункт меню "Выполнить". В появившемся окне введите в командной строке команду "cmd.exe" (разумеется, без кавычек) и нажмите кнопку "Ok" или "Enter". В открывшемся черном окне введите команду "set" и нажмите "Enter".</blockquote>
<br />Теперь, при входе в Ваше приложение, первым делом открываете эту служебную таблицу и ищете запись с полным набором идентификаторов, однозначно определяющих данный процесс. Если такой записи нет, то создаете ее.<br /><br />После того, как запись найдена (или создана) предпринимаете попытку ее заблокировать. Если это не удалось, то значит приложение уже запущено. Если требуется, тем не менее, разрешить повторный запуск приложения, то создаете еще одну строку с тем же набором реквизитов и блокируете эту новую строку.<br /><br />Теперь, когда Вам потребуется узнать, кто же в данный момент работает с приложением, Вы просто выполняете сканирование этой таблицы на предмет поиска тех записей, которые также заблокированы. Прочитав их реквизиты, Вы получите информацию о том, кто в данный момент работает с приложением.<br /><br />В коде это будет выглядеть примерно так.<br /><br />Служебная таблица имеет примерно такую структуру</li>
</ul>



<pre class="wp-block-preformatted">CREATE TABLE curProc (CurProcID I AutoInc, SYS0 C(128), LastTime T)
</pre>



<p>Здесь CurProcID - это код записи. В данном случае использовано тип данных Integer-Autoincrement, который был введен только в версии Visual FoxPro 8.0. Для младших версий FoxPro можно формировать код записи при помощи специальной функции NewId() или любым удобным для Вас способом.</p>



<p>Идентификатором процесса выступает сетевое имя компьютера SYS(0)</p>



<p>Тогда собственно код функции при открытии приложения будет таким</p>



<pre class="wp-block-preformatted"><pre class='bbcode'> * Запоминаю текущую сессию данных  
  LOCAL lnSessionCurrent  
  lnSessionCurrent = SET("DataSession")  
    
 * Проверяю факт создания частной сессии данных  
  IF Type("m.goSessionUsers") = "U"  
      PUBLIC goSessionUsers  
      goSessionUsers = CreateObject("Session")  
     * Перехожу в созданную сессию данных  
      Set DataSession To goSessionUsers.DataSessionId  
     * Выполняю настройки в этой сессии  
      SET REPROCESS TO 3      
      SET TALK OFF  
      SET MULTILOCK ON  
  Else  
     * Перехожу в частную сессию данных  
      Set DataSession To goSessionUsers.DataSessionId  
  EndIf  
    
 * Собственно поиск и блокировка записи  
  IF USED("curProc")=.F.  
      USE curProc IN 0 SHARED    
  ENDIF  
  SELECT curProc    
  LOCATE FOR SYS0 = SYS(0)    
  IF FOUND()=.F.    
      INSERT INTO curProc (SYS0) VALUES (SYS(0))    
  ENDIF    
    
  IF RLOCK()=.F.    
     * Запись блокирована другим процессом    
     * Т.е. предпринята попытка повторного запуска приложения    
  ELSE    
     * Записываю время входа    
      REPLACE LastTime WITH DateTime()    
  ENDIF    
    
 * Возвращаюсь в исходную сессию данных  
  Set DataSession To m. lnSessionCurrent  
    
</pre></pre>



<p>Снимать блокировку записи не надо до окончания работы приложения. В случае аварийного завершения приложения (сбой питания) снятие блокировки произойдет автоматически.</p>



<p>Если при закрытии приложения удалять (или очищать) созданную запись, то по факту наличия не заблокированной записи можно сделать вывод о том, что приложение было закрыто аварийно. И определить кем именно.</p>



<p>Запись времени нужна для того, чтобы не накапливался мусор. Например, уже нет компьютера со значением SYS(0), но запись с таким значением все еще существует. Вот по времени последнего обращения можно оценить: оставлять такую запись или уже пора удалять.</p>



<p>Теперь, собственно код, определяющий, кто же в данный момент работает с Вашим приложением.</p>



<pre class="wp-block-preformatted"><pre class='bbcode'> * Запоминаю текущую сессию данных  
  LOCAL lnSessionCurrent  
  lnSessionCurrent = SET("DataSession")  
    
 * Проверяю факт создания частной сессии данных  
  IF Type("m.goSessionUsers") = "U"  
     * Это ошибка.   
     * К моменту вызова данной функции частная сессия должна быть уже создана  
     * Поэтому прерываю процесс с сообщением об ошибке  
      MessageBox("Нет сессии данных служебной таблицы")  
      Return  
  Else  
     * Перехожу в частную сессию данных  
      Set DataSession To goSessionUsers.DataSessionId  
  EndIf  
    
 * Большинство настроек уже все выполнены при создании частной сессии данных   
 * в момент запуска приложения. Однако одну настройку следует установить  
 * не забыв сохранить исходное значение  
  LOCAL lnReporcess  
  lnReporcess = SET("REPROCESS")  
  SET REPROCESS TO 0 SECONDS    &amp;&amp; Спасибо Вадиму (piva) за подсказку ключевого слова SECONDS      
    
 * Создаю временную таблицу со структурой, дублирующей структуру служебной таблицы    
 * В эту временную таблицу будет записан результат поиска   
 * Опция READWRITE была введена только в версии Visual FoxPro 7  
 * Чтобы сделать курсор редактируемым в младших версиях FoxPro  
 * его придется переоткрыть повторно в другой рабочей области.  
 * Замечу также, что при таком запросе поле типа Integer-Autoincrement исходной таблицы  
 * конвертируется в поле с обычным типом Integer, что, в данном случае, как раз и требуется   
  USE IN SELECT('curCon')    
  SELECT * FROM curProc INTO CURSOR curCon NOFILTER READWRITE WHERE .F.    
        
 * Собственно поиск записей, заблокированных другими процессами    
  LOCAL laFields(1)    
  select curProc     
  SET ORDER TO 0    
  SCAN    
      IF IsRLocked() = .T. OR RLOCK() = .F.    
         * Эта запись содержит информацию о пользователе,     
         * использующем данное приложение в настоящий момент    
         * Копирую ее в итоговый курсор  
          SCATTER TO laFields    
          INSERT INTO curCon FROM ARRAY laFields    
      ELSE    
         * Поскольку удалось установить блокировку, то данная запись никем не используется  
         * Снимаю с нее блокировку и перехожу к следующей записи  
          UNLOCK RECORD Recno()    
      ENDIF    
  ENDSCAN    
    
 * Возвращаюсь к записи заблокированной при входе в текущую копию приложения  
  LOCATE FOR IsRLocked() = .T.    
    
 * Восстанавливаю исходную настройку текущей сессии  
  SET REPROCESS TO m.lnReporcess     
    
 * Отображение результата поиска    
  select curCon    
  GO TOP    
  BROWSE NOWAIT  
    
 * Возвращаюсь в исходную сессию данных  
  Set DataSession To m.lnSessionCurrent  
    
</pre></pre>



<p>Следует заметить, что курсор curCon существует только в той сессии данных, где он и был создан. Поэтому, вернувшись в исходную сессию данных, Вы уже не увидите результат поиска. Если Вы хотите отображать результат поиска в другой сессии данных, то либо следует использовать постоянную таблицу (это не очень хорошее решение), либо озаботится копированием информации из курсора в другую сессию данных. Это можно сделать, например, через массив.</p>



<p></p>



<pre class="wp-block-preformatted"><pre class='bbcode'>  LOCAL laStructure(1), laContent(1)  
    
  Select curCon    
 * Копирую структуру курсора в массив  
  =AFields(laStructure)  
 * Копирую содержимое курсора в массив  
  COPY TO ARRAY laContent  
 * Возвращаюсь в исходную сессию данных  
  Set DataSession To m.lnSessionCurrent  
 * Создаю новый курсор  
  CREATE CURSOR curCon FROM ARRAY laStructure  
 * Наполняю его данными из массива  
  APPEND FROM ARRAY laContent  
</pre></pre>



<p>У копирования содержимого курсора через массив есть ограничения. Кроме того, есть и другие способы копирования, но это выходит за рамки данной статьи.</p>



<p>Кроме факта проверки кто в данный момент работает с Вашим приложением служебную таблицу можно использовать как способ ограничения количества одновременно работающих пользователей. Просто запретите создавать в этой таблице новые записи. Выделите, например, только 100 записей. Это и будет означать не более 100 одновременных подключений к Вашему приложению.</p>



<p><strong>Смотрите также</strong></p>



<p><a target="_blank" rel="noreferrer noopener" href="https://forum.foxclub.ru/read.php?32,177252,177253#msg-177253">Как предотвратить повторный запуск приложения</a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kto-v-dannyj-moment-rabotaet-s-prilozheniem/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Администрирование приложения]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-predotvratit-povtornyj-zapusk-prilozheniya-2/</link>
					<title><![CDATA[Как предотвратить повторный запуск приложения]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Tue, 29 Nov 2022 06:43:17 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как предотвратить повторный запуск приложения</h1>
													</header>
													
<blockquote><b>Вопрос:<br /></b>Как предотвратить повторный запуск приложения?</blockquote>
<br /><br /><b>Ответ:</b><br /><br />Это один из тех вопросов, которые легко задать, но трудно ответить. Трудно не потому, что он очень уж сложный, а потому, что ответ на него требует некоторых пояснений того, что именно и почему необходимо сделать.<br />Для начала, следует определиться с тем, что именно Вы вкладываете в понятие "повторный запуск приложения". Например:<br /><br />
<ul>
<li>Запуск одного и того же приложения на одном компьютере вне зависимости от логина пользователя</li>
<li>Запуск одного и того же приложения на одном компьютере из одной сессии в терминальном режиме</li>
<li>Запуск одного и того же приложения с разных компьютеров с логином одного пользователя</li>
<li>Работа с базой данных из разных приложений, но с логином одного пользователя<br /><br />И это далеко не полный перечень самых разных ситуаций, которые могут подразумеваться под термином "повторный запуск приложения".<br /><br />Собственно, вопрос сводится к набору признаков, по которому Вы хотите идентифицировать приложение. Причем эти признаки должны быть такими, которые однозначно определяются в момент открытия приложения и не могут быть изменены в процессе работы приложения.<br /><br />Именно поэтому, наиболее распространенный способ определения приложения по его заголовку не может служить таким уникальным идентификатором. По крайней мере, сам по себе. Без каких-либо дополнительных признаков. Просто потому, что заголовок окна приложения легко может быть изменен в процессе работы приложения или же один и тот же заголовок могут иметь разные приложения. Разные в том смысле, который Вы вкладываете в это понятие.<br /><br />Уникальными идентификаторами могут являться:<br /><br /></li>
<li>SYS(0) – Идентификатор компьютера и логин пользователя при входе в Windows</li>
<li>Логин пользователя при входе в Ваше приложение</li>
<li>Дата и время последнего входа в Ваше приложение</li>
<li>GetEnv("SessionName") – имя сессии, в которой запущено приложение. Имеет смысл при работе в терминальном режиме, поскольку значение, возвращаемое функцией SYS(0) будет одинаковым, но имя сессии - разным.<br /><br />Вам могут понадобиться и другие идентификаторы, формируемые либо внутри Вашего приложения, либо самой операционной системой для того, чтобы однозначно определить уникальный экземпляр приложения. Какие именно – решайте сами исходя из Вашей задачи.<br /><br />
<blockquote><strong>Замечание</strong><br />Функция GetEnv() возвращает значение переменной созданной операционной системой. Полный список таких переменных и их значение можно посмотреть из режима командной строки Windows. Нажмите кнопку "Пуск" и выберите пункт меню "Выполнить". В появившемся окне введите в командной строке команду "cmd.exe" (разумеется, без кавычек) и нажмите кнопку "Ok" или "Enter". В открывшемся черном окне введите команду "set" и нажмите "Enter".</blockquote>
<br />Теперь, когда Вы определились с набором признаков, идентифицирующих Ваше приложение, встает следующий вопрос: как и где, хранить этот набор, чтобы он был доступен из другого приложения?<br /><br />Это "хранилище" реквизитов должно удовлетворять следующим требованиям:<br /><br /><b>1.</b> Формироваться в момент открытия приложения<br /><b>2.</b> Быть недоступным для изменения из другого приложения в процессе работы приложения, его создавшего. Однако должно быть доступным на чтение.<br /><b>3.</b> Очищаться при закрытии приложения. Даже если закрытие приложения произошло в аварийном режиме (сбой питания)<br /><br />Ну, очевидно, идеальным вариантом такого хранилища является само приложение. Точнее, набор переменных памяти, которые создает само приложение.<br /><br />Однако использовать напрямую приложение затруднительно. По ряду причин. Например, при таком подходе необходимо будет просканировать вообще все открытые приложения. Ведь заранее неизвестно, какое именно приложение нам нужно найти. Есть и другие причины.<br /><br />Но, тем не менее, существует довольно простое решение данной проблемы. Это использование так называемых, объектов-семафоров. Эти объекты создаются при помощи специальных API-функций и их можно "увидеть" извне приложения. Т.е. любое другое приложение может сразу определить, существует ли искомый объект или нет.<br /><br />Поскольку в данном случае необходимо определить существование одного и только одного экземпляра приложения, то лучше всего использовать объект <b>Mutex</b>. Свое название он получил от выражения "mutually exclusive", что означает "взаимно исключающий".<br /><br />
<blockquote><strong>Замечание</strong><br />Если у Вас стоит задача допустить существование фиксированного количества одновременно запущенных экземпляров приложений, то можно использовать объект Semaphore. Но организационно это значительно сложнее.</blockquote>
<br />Полное описание способов использования объекта Mutex смотрите в библиотеке MSDN на сайте Microsoft. В данном случае будет описан один единственный способ, реализующий необходимую функциональность.<br /><br />Прежде, чем использовать объект Mutex в приложении, необходимо объявить API-функцию для его создания с именем CreateMutex.</li>
</ul>



<pre class="wp-block-preformatted"><pre class='bbcode'>  Declare Integer CreateMutex In Win32API ;  
      Integer lpMutexAttributes, ;  
      Integer bInitialOwner, ;  
      String lpName  
    
</pre></pre>



<p><em>lpMutexAttributes</em>&nbsp;– атрибуты защиты. В данном случае не используются, поэтому значение этого параметра устанавливается в 0.</p>



<p><em>bInitialOwner</em>&nbsp;– начальное состояние объекта в момент инициализации. Значение 1 означает, что приложение создавшее объект становится владельцем этого объекта. Значение 0 означает, что приложение только создает объект, но не владеет им. В данном случае всегда следует использовать значение 1.</p>



<p><em>lpName</em>&nbsp;– имя объекта. Не должно содержать символа "\" и общая длина не должна превышать 260 символов (MAX_PATH). Регистр букв (большие или маленькие) имеет значение. Т.е для объекта&nbsp;<strong>Mutex</strong>&nbsp;большие и маленькие буквы – это разные буквы.</p>



<p>Именно имя и будет являться тем уникальным идентификатором, по значению которого и будет определяться факт существования приложения с определенными значениями реквизитов. Само имя – это символьная строка "сложенная" из значений необходимых идентификаторов. Исключая символ "\" и длиной не более 260 символов.</p>



<p><strong>Замечание</strong></p>



<p>В терминальном режиме все объекты ядра (kernel), в том числе и объект&nbsp;<strong>mutex</strong>, работают в так называемом "пространстве имен". В терминах FoxPro можно сказать, что они имеют определенную "область видимости". По умолчанию, они имеют "область видимости" Session. Это значит, что они "видны" только в той терминальной сессии, в которой и были созданы. Другая сессия (другой пользователь) уже их не видит.</p>



<p>Чтобы созданный объект&nbsp;<strong>Mutex</strong>&nbsp;был виден из других сессий ему надо задать пространство имен Global. Это делается добавлением префикса "Global\" к сформированному имени. Т.е. имя будет выглядеть так:</p>



<p>lpName = "Global\Имя_объекта"</p>



<p>Подробнее о пространстве имен объектов ядра в терминальном режиме читайте здесь&nbsp;<a target="_blank" rel="noreferrer noopener" href="http://msdn.microsoft.com/en-us/library/aa382954(VS.85).aspx"><u>Kernel Object Namespaces</u></a></p>



<p>Функция&nbsp;<strong>CreateMutex</strong>&nbsp;возвращает так называемый, "хендл" или идентификатор объекта. Целое число. Однако данная функция может, как создать объект, так и вернуть ссылку на уже существующий объект созданный ранее другим приложением.</p>



<p>Чтобы определить, был ли объект&nbsp;<strong>Mutex</strong>&nbsp;действительно создан или Вы получили ссылку на ранее созданный объект, следует использовать другую API-функцию с именем&nbsp;<strong>GetLastError</strong>.</p>



<p>Если эта функция вернет значение 183 (ERROR_ALREADY_EXISTS), то это и будет означать тот факт, что объект&nbsp;<strong>Mutex</strong>&nbsp;с тем же именем уже был ранее создан. Т.е. было ранее запущено приложение с теми же реквизитами.</p>



<p>В принципе, объект&nbsp;<strong>Mutex</strong>&nbsp;и все ссылки на него автоматически удаляются при закрытии приложения. Поэтому можно и не давать специальные команды по удалению этого объекта из памяти. Но уборка за собой является хорошим тоном в программировании. Поэтому, лучше все-таки выполнить удаление объекта&nbsp;<strong>Mutex</strong>&nbsp;при закрытии приложения.</p>



<p>Простейший код использования объекта&nbsp;<strong>Mutex</strong>&nbsp;для проверки факта существования ранее запущенного приложения будет выглядеть примерно так.</p>



<pre class="wp-block-preformatted"><pre class='bbcode'> * Формируем идентификатор данного приложения  
  LOCAL lcApplicationName  
  lcApplicationName = GetEnv("SessionName") + "#"+ SYS(0)  
    
 * Формируем ссылку на объект Mutex  
  Declare Integer CreateMutex In Win32API ;  
      Integer lpMutexAttributes, ;  
      Integer bInitialOwner, ;  
      String lpName  
    
  PUBLIC gnMutex  
  gnMutex = CreateMutex(0,1,m.lcApplicationName)  
    
 * Проверяем факт существования объекта Mutex с тем же именем  
  #DEFINE ERROR_ALREADY_EXISTS 183  
  Declare integer GetLastError In Win32API  
    
  If GetLastError() = ERROR_ALREADY_EXISTS  
     * Приложение уже запущено  
     * Надо вывести ранее запущенное приложение на передний план  
     * или сообщить об этом факте пользователю  
     * и закрыть текущее приложение  
      Do CloseMutex with .T.  
      Return  
  EndIf  
    
 * Если объект Mutex был именно создан, то нет ранее запущенного приложения   
 * и можно запускать текущее приложение  
    
  ...  
  READ EVENTS  
    
 * По окончании работы приложения надо удалить объект Mutex, хотя это и не обязательно  
  Do CloseMutex with .F.  
  Return  
    
 * Процедура удаления объекта Mutex  
  Procedure CloseMutex  
  LParameters IsExists    &amp;&amp; существует ли другое приложение  
    
 * Если другое приложение существует, то удалять объект Mutex не надо  
 * Удаление выполняется только если объект был создан именно в этом приложении  
  If IsExists = .f.  
     * Удаление объекта Mutex  
      Declare integer ReleaseMutex IN Win32API Integer hMutex  
      ReleaseMutex(m.gnMutex)  
  EndIf  
    
 * Закрытие уже не нужного хендла объекта Mutex  
  Declare integer CloseHandle IN Kernel32 Integer hObject  
  CloseHandle(m.gnMutex)  
    
  EndProc  
</pre></pre>



<p>Однако, несмотря на все достоинства использования объекта Mutex, его использование имеет и недостатки. Дело в том, что данный объект существует только и исключительно в памяти того компьютера, в котором он был создан.</p>



<p>В большинстве случаев это не является проблемой, поскольку требуется проконтролировать факт повторного запуска приложения на одном и том же компьютере. Но если Вам надо контролировать факт запуска приложения, например, одного и того же пользователя, но с разных компьютеров, то использование объекта Mutex не решает проблему.</p>



<p>Возвращаясь к требованиям, предъявляемым к "хранилищу" реквизитов приложения по которым определяется факт запуска приложения, дополняем его еще одним требованием.</p>



<p><strong>4.</strong>&nbsp;Оно должно быть доступным для чтения с разных компьютеров.</p>



<p>В принципе, можно реализовать и это требование при помощи объекта Mutex, если создавать его всегда только на том компьютере, где хранятся общие данные приложения. Т.е. создавать этот объект на сервере. Это можно реализовать, создав специальную библиотеку Com+. Но описание данной технологии выходит за рамки данной стать. Кроме того, есть другой способ.</p>



<p>Дело в том, что в самой среде FoxPro есть механизм взаимодействия нескольких пользователей одного приложения. Это блокировки. Ведь запись, заблокированную одним пользователем невозможно изменить другим пользователем, хотя можно прочитать из нее информацию.</p>



<p>Это значит, что если создать специальную таблицу, включенную в базу данных, записи которой будут содержать информацию о факте запуска приложения, то, наложив блокировку на соответствующую запись, можно дать знать другим экземплярам приложения кто уже работает с приложением.</p>



<p>Чтобы операции с этой служебной таблицей не мешали основной работе приложения, лучше открывать ее в отдельной сессии данных. Это можно сделать, например, используя объект Session, введенный в Visual FoxPro 6.0 Service Pack 3. Для младших версий FoxPro придется очень аккуратно следить за установкой и снятием блокировок с таблиц. Т.е. за командами UNLOCK, RLOCK(), LOCK(), SET MULTILOCKS. Хотя, можно использовать невидимую форму.</p>



<p>Итак, в базе данных создается еще одна таблица. Это обычная таблица, принадлежащая базе данных. Т.е. таблица, лежащая на сервере, а не на локальном компьютере пользователя.</p>



<p>Список полей этой таблицы является набором идентификаторов, по которым в Вашей задаче надо отделять процессы друг от друга. Это может быть, например:</p>



<p>SYS(0) – Идентификатор компьютера и логин пользователя при входе в Windows<br>Логин пользователя при входе в Ваше приложение<br>Дата и время последнего входа в Ваше приложение<br>GetEnv("SessionName") – имя сессии, в которой запущено приложение.</p>



<p>Теперь, при входе в Ваше приложение, первым делом открываете эту служебную таблицу и ищете запись с полным набором идентификаторов, однозначно определяющих данный процесс. Если такой записи нет, то создаете ее.</p>



<p>После того, как запись найдена (или создана) предпринимаете попытку ее заблокировать. Если это не удалось, то значит приложение уже запущено.</p>



<p>В коде это будет выглядеть примерно так.</p>



<p>Служебная таблица имеет примерно такую структуру</p>



<pre class="wp-block-preformatted">CREATE TABLE curProc (CurProcID I AutoInc, SYS0 C(128), LastTime T)
</pre>



<p>Здесь CurProcID - это код записи. В данном случае использовано тип данных Integer-Autoincrement, который был введен только в версии Visual FoxPro 8.0. Для младших версий FoxPro можно формировать код записи при помощи специальной функции NewId() или любым удобным для Вас способом.</p>



<p>Идентификатором процесса выступает сетевое имя компьютера SYS(0)</p>



<p>Тогда собственно код функции будет таким</p>



<pre class="wp-block-preformatted"><pre class='bbcode'> * Запоминаю текущую сессию данных  
  LOCAL lnSessionCurrent  
  lnSessionCurrent = SET("DataSession")  
    
 * Проверяю факт создания частной сессии данных  
  IF Type("m.goSessionUsers") = "U"  
      PUBLIC goSessionUsers  
      goSessionUsers = CreateObject("Session")  
     * Перехожу в созданную сессию данных  
      Set DataSession To goSessionUsers.DataSessionId  
     * Выполняю настройки в этой сессии  
      SET REPROCESS TO 3  
      SET TALK OFF  
      SET MULTILOCKS ON  
  Else  
     * Перехожу в частную сессию данных  
      Set DataSession To goSessionUsers.DataSessionId  
  EndIf  
    
 * Собственно поиск и блокировка записи  
  IF USED("curProc") = .F.  
      USE curProc IN 0 SHARED   
  ENDIF   
  SELECT curProc    
  LOCATE FOR SYS0 = SYS(0)    
  IF FOUND()=.F.    
      INSERT INTO curProc (SYS0) VALUES (SYS(0))    
  ENDIF    
    
  IF RLOCK()=.F.    
     * Запись блокирована другим процессом    
     * Т.е. предпринята попытка повторного запуска приложения    
  ELSE    
     * Записываю время входа    
      REPLACE LastTime WITH DateTime()    
  ENDIF    
        
 * Возвращаюсь в исходную сессию данных  
  Set DataSession To m.lnSessionCurrent  
</pre></pre>



<p>Снимать блокировку записи не надо до окончания работы приложения. В случае аварийного завершения приложения (сбой питания) снятие блокировки произойдет автоматически.</p>



<p>Если при закрытии приложения удалять (или очищать) созданную запись, то по факту наличия не заблокированной записи можно сделать вывод о том, что приложение было закрыто аварийно. И определить кем именно.</p>



<p>Запись времени нужна для того, чтобы не накапливался мусор. Например, уже нет компьютера со значением SYS(0), но запись с таким значением все еще существует. Вот по времени последнего обращения можно оценить: оставлять такую запись или уже пора удалять.</p>



<p>Также эту таблицу можно использовать для получения сведений о том, кто в данный момент работает с приложением</p>



<p><strong>Смотрите также</strong></p>



<p><a target="_blank" rel="noreferrer noopener" href="https://forum.foxclub.ru/read.php?32,177182,258927#msg-258927">Как вывести приложение на передний план</a><br><a target="_blank" rel="noreferrer noopener" href="http://www.hot.ee/jurisfox/vfp60/remarks_02_ru.htm">Заметки на сайте Юрия Шутенко</a><br><a target="_blank" rel="noreferrer noopener" href="http://msdn.microsoft.com/en-us/library/aa382954(VS.85).aspx">Kernel Object Namespaces</a></p>


<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-predotvratit-povtornyj-zapusk-prilozheniya-2/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Администрирование приложения]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/propadayut-nastrojki-grid-sobytiya-stolbczov-zagolovkov-yacheek/</link>
					<title><![CDATA[Пропадают настройки Grid, события столбцов, заголовков, ячеек]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Sat, 19 Nov 2022 12:23:12 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Пропадают настройки Grid, события столбцов, заголовков, ячеек</h1>
													</header>
													<blockquote><p><b>Проблема<br />
</b>В дизайнере формы были сделаны настройки Grid, написана собственная обработка события Header.Click() или Column.Text1.Click(). Однако при выполнении программы все эти настройки пропадают.</p></blockquote>
<p><b>Причина</b><br />
Это происходит после переоткрытия источника данных для Grid. Того, что указано в качестве Grid.RecordSource. Т.е. эта таблица была закрыта и открыта заново. Как правило, это является следствием использования команды PACK, но могут быть и более сложные варианты.</p>
<p><b>Решение</b><br />
Прежде всего, следует заметить, что использование команды PACK в активной форме - это порочная практика. Физическое удаление записей следует вынести в отдельную служебную процедуру, периодически запускаемую администратором.</p>
<p>Тем не менее, если подобная задача все-таки необходима, то <u>перед</u> переоткрытием (или заменой) источника данных для Grid его следует сбросить.</p>
<p></p>
<pre>
* Сброс источника данных Grid
ThisForm.Grid1.RecordSource = ""
* Выполнение переоткрытия таблицы, модификация данных, выбор другой таблицы
...
* Восстановление источника данных Grid
ThisForm.Grid1.RecordSource = "Table"
ThisForm.Grid1.Column1.ControlSource = "Table.Field1"
ThisForm.Grid1.Column2.ControlSource = "Table.Field2"
ThisForm.Grid1.Column3.ControlSource = "Table.Field3"</pre>
<p>В случае необходимости, можно автоматизировать процесс сохранения и восстановления настроек источника данных столбцов Grid. Подробнее об этом способе читайте в статье</p>
<p><a target="_blank" rel="nofollow noopener" href="https://foxclub.ru/knowledgebase/vfp-grid-chast-i/"><u>VFP грид, часть I</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/propadayut-nastrojki-grid-sobytiya-stolbczov-zagolovkov-yacheek/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Grid]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-v-dizajnere-vstavit-obekt-v-stolbecz-grid/</link>
					<title><![CDATA[Как в дизайнере вставить объект в столбец Grid]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Sat, 19 Nov 2022 09:21:39 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как в дизайнере вставить объект в столбец Grid</h1>
													</header>
													
<blockquote class="wp-block-quote"><p><strong>Вопрос</strong></p><p>Как в дизайнере формы я могу вставить нужный мне объект (ComboBox, CheckBox, Image, CommandButton, свой класс и т.п.) в столбец Grid?</p></blockquote>



<p><strong>Ответ</strong></p>



<ul><li>Добавляете на форму объект Grid</li><li>Устанавливаете у него свойство ColumnCount больше нуля</li><li>Правой клавишей мыши щелкаете на Grid и выбираете пункт Edit. В старших версиях FoxPro в этот режим можно перейти, нажав и удерживая клавишу Ctrl щелкнув по Grid левой клавишей мыши</li><li>В ToolBar с именем Form Controls щелкните левой клавишей мыши по нужному объекту</li><li>Левой клавишей мыши щелкаете на нужном столбце в любом месте под заголовком</li></ul>



<p>Все, нужный объект вставлен. Убедится в это можно в окне Poperties. В раскрывающемся списке в соответствующем столбце Grid кроме объекта Text1 появиться и имя вставленного Вами объекта с добавлением окончания 1.</p>



<p>Чтобы именно вставленный объект отображался в столбце, необходимо убедится, что свойство&nbsp;<strong>CurrentControl</strong>&nbsp;этого столбца содержит имя вставленного объекта.</p>



<p>А чтобы вставленный Вами объект отображался не только в текущей строке Grid, но и во всех остальных строках необходимо для того же столбца сделать дополнительную настройку</p>



<pre class="wp-block-code"><code>Sparse = .F.</code></pre>



<p>Можно также использовать другой метод вставки</p>



<ul><li>Добавляете на форму объект Grid</li><li>Устанавливаете у него свойство ColumnCount больше нуля</li><li>Добавьте экземпляр любого нужного Вам класса, который Вы хотите вставить в столбец Grid непосредственно на форму вне Grid</li><li>Выделите добавленный объект (щелкнув по нему левой клавишей мыши) и скопируйте его в буфер обмена (комбинация клавиш Ctrl+C или пункт системного меню Edit, подпункт Copy)</li><li>Правой клавишей мыши щелкаете на Grid и выбираете пункт Edit. В старших версиях FoxPro в этот режим можно перейти, нажав и удерживая клавишу Ctrl щелкнув по Grid левой клавишей мыши</li><li>Левой клавишей мыши щелкаете на нужном столбце в любом месте под заголовком</li><li>Сделайте вставку из буфера обмена (комбинация клавиш Ctrl+V или пункт системного меню Edit, подпункт Paste)</li></ul>



<p>Можно удалить уже не нужный объект Text1 из столбца Grid следующим образом:</p>



<ul><li>В окне Properties в раскрывающемся списке выберите объект, который хотите удалить</li><li>Один раз&nbsp;щелкните левой клавишей мыши по любому месту формы. Лучше щелкнуть по заголовку формы, хотя это не принципиально.</li><li>Нажмите клавишу Delete на клавиатуре</li></ul>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-v-dizajnere-vstavit-obekt-v-stolbecz-grid/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Grid]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/v-detalyah-otcheta-chastichno-sedaetsya-informacziya/</link>
					<title><![CDATA[В деталях отчета частично &#8220;съедается&#8221; информация]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Mon, 07 Nov 2022 05:30:05 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>В деталях отчета частично &#8220;съедается&#8221; информация</h1>
													</header>
													<p><strong>Проблема</strong></p>
<blockquote>
<p>Случалось ли кому сталкиваться с такой историей:<br />
в деталях отчета частично "съедается" информация. Например, типовой отчет типа "счет", наименование товара может может занять от 1 до 4-х строк. До 2-х включительно все хорошо. Но если 4-ре строки, то начинается мистика:<br />
в документе, где много наименований (товаров), часть информации просто на полуслове теряется. Те же наименования в том же отчете, но в документе с 2...3 товарами, отображаются корректно.</p>
</blockquote>
<p><strong>Ответ</strong></p>
<p>Для «обрезанного» поля надо задать длину либо cast(... as c(254)) либо padr(..., 254) либо Memo</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/v-detalyah-otcheta-chastichno-sedaetsya-informacziya/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Report (Отчеты)]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-opredelit-v-kakom-vfp-sdelano-prilozhenie/</link>
					<title><![CDATA[Как определить в каком VFP сделано приложение]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Sun, 06 Nov 2022 06:48:03 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как определить в каком VFP сделано приложение</h1>
													</header>
													<blockquote>
<p>А как определить в каком VFP сделанно приложение либо при установки последних библиотек это не имеет значения ?</p>
</blockquote>
<p>Открываете файл EXE как текстовый файл (можно в блокноте Notepad) и где-то в самом начале этого файла должна быть строка "VisualFoxProRuntime". Сразу за ней после точки будет стоять цифра, обозначающая номер версии FoxPro в которой был скомпилирован данный EXE. Для VFP9 это будет строка "VisualFoxProRuntime.9"</p>
<p>Однако проблема в том, что таким образом можно узнать только собственно версию без определения ServicePack. А при запуске приложения нужны RunTime библиотеки с точностью именно до ServicePack. Например, если приложение было скомпилировано в VFP9SP1, то и RunTime библиотеки должны быть от VFP9SP1. Если будут установлены библиотеки VFP9SP2, то будет аналогичное сообщение об ошибке.</p>
<p>Вам придется либо поискать библиотеки и просто их скопировать в папку с EXE, либо действовать методом "научного тыка".</p>
<p>1. Установить "голый" VFP9. Проверить работоспособность<br />
2. Если не работает, накатить SP1. Проверить<br />
3. Если не работает, деинсталировать VFP9, снова установить и накатить SP2.</p>
<p>Накатить SP2 поверх SP1 - не получится. В рекомендациях по установке советуют деинсталировать VFP9SP1, а потом устанавливать отдельно VFP9 с последующей установкой SP2</p>
<p>Да, нужна еще сишная библиотека msvcr71.dll. Эту библиотеку надо регистрировать через regsvr32.</p>
<p>Для старта приложения необходимый "минимум": msvcr71.dll, vfp9r.dll, vfp9renu.dll</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-opredelit-v-kakom-vfp-sdelano-prilozhenie/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pochemu-v-gotovom-exe-ne-rabotaet-kopirovanie-po-ctrl-c-ctrl-v-2/</link>
					<title><![CDATA[Почему в готовом EXE не работает копирование по Ctrl+C, Ctrl+V]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Sun, 18 Dec 2022 06:29:19 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Почему в готовом EXE не работает копирование по Ctrl+C, Ctrl+V</h1>
													</header>
													<p><b>Проблема</b></p>
<p>На этапе разработки приложения работало копирование через буфер обмена (горячие клавиши Ctrl+C, Ctrl+V), но в готовом файле EXE эти комбинации клавиш не работают. Как можно исправить эту ситуацию?</p>
<p>Причина и решение проблемы приведены в разделе посвященном меню</p>
<p><a href="/faq/chavo/menu/" target="_blank" rel="nofollow noopener"><u>Почему в готовом EXE не работает копированиепо Ctrl+C, Ctrl+V</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pochemu-v-gotovom-exe-ne-rabotaet-kopirovanie-po-ctrl-c-ctrl-v-2/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-prikrepit-k-fajlu-exe-svoyu-ikonku/</link>
					<title><![CDATA[Как прикрепить к файлу EXE свою иконку]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Mon, 31 Oct 2022 10:20:29 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как прикрепить к файлу EXE свою иконку</h1>
													</header>
													<blockquote>
<p><b>Вопрос<br />
</b>Я создал EXE-файл. Однако в проводнике Windows и на рабочем столе связанная с моим файлом иконка - это либо лисья мордочка, либо иконка флага Windows. Как мне прикрепить к моему файлу EXE нужную мне иконку.</p>
</blockquote>
<p><b>Ответ<br />
</b>Сам факт прикрепления иконки к EXE-файлу можно организовать двумя способами:</p>
<p>
</p>
<ol>
<li>Воспользоваться пунктом основного меню "Project" - "Project info" - закладка "Project" - поставить "птичку" в пункте "Attach icon" и выбрать нужную иконку
</li>
<li>Программно, в главном (стартовом) файле дать команду
<p>_SCREEN.icon = "MyIcon.ico"</p>
</li>
</ol>
<p>
Эти два способа не взаимозаменяемые, а взаимодополняющие.</p>
<p>Добавление иконки в свойствах проекта отвечает за отображение иконки в тех случаях, когда собственно программа не запускается. В проводнике Windows или ярлык на рабочем столе.</p>
<p>Указание иконки для объекта _SCREEN определяет изображение в левом верхнем углу основного окна приложения, если приложение использует окно _SCREEN в качестве основного окна приложения.</p>
<p><b>Замечание</b></p>
<p>Если Вы создаете приложение на базе форм со свойством Form.ShowWindow = 2 - As Top-Level, то необходимо будет прикрепить соответствующую иконку к свойству самой формы</p>
<p>Form.icon = "MyIcon.ico"</p>
<p>Поскольку в этом случае нет основного окна FoxPro с именем _SCREEN. Соответственно, не будут отображаться и иконки прикрепленные к этому окну. Вместо него отображается Ваша форма со свойством As Top-Level</p>
<p>
Однако каким бы способом Вы ни воспользовались, необходимая иконка должна быть доступна к моменту ее использования. Лучше включить ее внутрь проекта. Т.е. добавить в сам проект на закладку "Other" в группу "Other Files"</p>
<p>Ассоциируемая иконка должна обладать следующими свойствами:</p>
<ul>
<li>Иконка - это именно иконка. Т.е. файл с расширением "ico"</li>
<li>Иконка (сам файл ico) должна содержать в себе две картинки - 16х16 пикселей и 32х32 пикселей</li>
<li>Иконка должна иметь столько цветов, сколько поддерживает как текущая версия FoxPro, так и операционная система Windows.</li>
<li>Файл EXE должен быть собран (создан) в той версии операционной системы Windows, которая указана в системных требованиях к Вашей версии FoxPro.
<p>В принципе, FoxPro поддерживает отображение иконок 3 размеров: 16х16, 32х32 и 48х48. Однако размер 48х48 практически нигде не используется. Впрочем, можете также включить иконку размера 48х48 в свой файл ico. Хотя практического смысла это не имеет.</p>
<p>Также FoxPro поддерживает изображение иконок в 4 наборах цветов: 16 Color, 256 Color, True Color (16 bit), True Color (24 bit). Для своей иконки лучше использовать минимальный цветовой набор - 16 Color или 256 Color. Мало ли, какие установки будут сделаны на машине клиента. А 256 Color поддерживают практически все видео карты.</p>
<p>Если в системных требованиях для Вашей версии FoxPro указано, что разработка приложения должна осуществляться в версии Windows 2000 или Windows XP, то не стоит пытаться собрать готовый файл EXE в младшей версии. Например, в Windows 98. Вполне возможно, что Вы получите работоспособный файл EXE, но, скорее всего, "в комплекте" Вы получите массу глюков. Например, не будет отображаться присоединенная иконка.</li>
</ul>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-prikrepit-k-fajlu-exe-svoyu-ikonku/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/chast-bukv-pri-vvode-zamenyayutsya-latinskimi/</link>
					<title><![CDATA[Часть букв при вводе заменяются латинскими]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Mon, 31 Oct 2022 10:18:47 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Часть букв при вводе заменяются латинскими</h1>
													</header>
													<blockquote>
<p><b>Проблема</b><br />
При отладке приложения все в порядке, а в готовом файле EXE в процессе ввода часть русских букв автоматически заменяются латинскими буквами</p>
<p>
<b>Причина</b><br />
Причина в несовпадении кодовых страниц.</p>
</blockquote>
<p>По умолчанию, если кодовая страница не указана явно, то до версии Visual FoxPro 6 включительно, и на этапе отладки приложения и в готовом файле EXE кодовая страница устанавливается такая же, как и кодовая страница Windows.</p>
<p>Однако, начиная с версии Visual FoxPro 7, на этапе отладки кодовая страница по-прежнему устанавливается как кодовая страница Windows, но в готовом файле EXE будет установлена кодовая страница 1252 (Windows ANSI)</p>
<p><b>Решение</b></p>
<p>Необходимо явно указать в какой кодовой странице следует работать. Это можно сделать одним единственным способом.<br />
Надо создать файл конфигурации CONFIG.FPW. Это обычный текстовый файл. И написать в нем строчку</p>
<pre>CODEPAGE=1251</pre>
<p>Файл конфигурации можно подключить несколькими способами. Наиболее распространенными являются три варианта.</p>
<p>
</p>
<ol>
<li>Включить файл конфигурации внутрь файла EXE.
<p>Для этого добавьте файл конфигурации в Ваш проект на закладке "Other" в раздел "Text Files". И убедитесь, что слева от имени файла нет значка перечеркнутого кружка.</p>
<p>Все. Теперь файл конфигурации станет частью готового файла EXE и поставлять его клиенту как отдельный файл нет необходимости. Однако следует понимать, что такой файл невозможно будет изменить у клиента.</p>
</li>
<li>Положить файл конфигурации рядом с файлом EXE в ту же директорию
<p>По умолчанию, в момент запуска файла EXE, если файл конфигурации не включен внутрь файла EXE, то файл конфигурации будет подхвачен из той же директории, в которой находится файл EXE</p>
</li>
<li>Использовать специальный ключ, для указания пути доступа к файлу конфигурации
<p>Для явного указания пути доступа к файлу конфигурации можно использовать специальный именованный параметр (ключ). Примерно в таком синтаксисе</p>
<div class="foxcode">
<div class="num_w"> </div>
<pre class="bbcode">MyProg.EXE -C"C:\MyDir\Config.fpw"</pre>
</div>
<p>
Подробнее о передаче параметров файл EXE читайте в статье:</p>
<p><a href="/knowledgebase/glavnyj-startovyj-fajl-proekta/" target="_blank" rel="nofollow noopener"><u>Главный (стартовый) файл. Передача параметров в EXE</u></a></li>
</ol>
<p><b>Замечание</b></p>
<p>Для версий до Visual FoxPro 5 включительно, следует также поставлять клиенту файл</p>
<p>FOXPRO.INT</p>
<p>Не надо путать его с ini-файлом, расширение от слова "international". Этот файл поставлялся вместе с FoxPro в его корневой директории. Его необходимо класть рядом с файлом EXE на машине клиента. Включать его внутрь файла EXE нельзя. Начиная с версии VFP6, надобность в нем отпала. Он уже не нужен.</p>
<p>Дополнительную информацию о возможных ошибках связанных с кодовыми страницами можете почитать здесь</p>
<p><a href="/knowledgebase/nevernoe-otobrazhenie-otdelnyh-simvolov-ili-nesovpadenie-kodovyh-stranicz/" target="_blank" rel="nofollow noopener"><u>Неверное отображение отдельных символов или несовпадение кодовых страниц</u></a><br />
<a href="http://vfpdev.narod.ru/docs/mtscom_r.html#cpproblem" target="_blank" rel="nofollow noopener"><u>Проблема CODEPAGE у VFPxT.DLL</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/chast-bukv-pri-vvode-zamenyayutsya-latinskimi/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/ne-zapuskaetsya-fajl-pomoshhi-v-chm-formate/</link>
					<title><![CDATA[Не запускается файл помощи в CHM-формате]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Mon, 31 Oct 2022 10:14:09 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Не запускается файл помощи в CHM-формате</h1>
													</header>
													<blockquote>
<p><strong>Проблема<br />
</strong>На машине клиента не запускается HELP, написанный в CHM-формате.</p>
<p><strong>Причина<br />
</strong>Приложение, написанное на FoxPro для работы с файлами в CHM-формате использует как ряд системных библиотек операционной системы, так и специфические дополнительные библиотеки, для организации вызова справки именно из приложений FoxPro.</p>
</blockquote>
<p>Соответственно, могут быть две причны:</p>
<p>При установке операционной системы Windows не были установлены библиотеки для работы с файлами в CHM-формате<br />
При переносе приложения на машину клиента не были установлены дополнительные библиотеки для работы с файлами в CHM-формате</p>
<p>
<strong>Решение</strong></p>
<p>Способ решения зависит от причины.</p>
<p>При установке операционной системы Windows не были установлены библиотеки для работы с файлами в CHM-формате</p>
<p>Для коректной работы CHM-файлов непосредственно в операционной среде Windows нужны следующие файлы</p>
<pre class="">
HHCTRL.OCX - элемент управления ActiveX HTML help (требует регистрации)
ITSS.DLL - Модуль DLL для компилированного HTML (требует регистрации)
ITIRCL.DLL - Модуль DLL для выполнения операций текстового поиска (требует регистрации)
HH.EXE - Программа просмотра HTML-документа</pre>
<p>Как правило, файлы OCX и DLL кладут в папку C:\Windows\System32, а файл HH.EXE непосредственно в папку C:\Windows</p>
<p>Обычно никакой специальной установки для этих файлов не требуется. Они и так уже установлены в Windows. Но если созданный Вами файл CHM не открывается в самой операционной среде Windows (например, из проводника), то это означает, что проблема связана именно с этими файлами.</p>
<p>Все эти четыре файла можно установить специальной программой HHUPD.EXE, поставляемой вместе с FoxPro в директории программы HTML Help Workshop. Или скачать ее с сайта Microsoft. Т.е. запуск программы HHUPD.EXE на машине клиента должен привести к установке этих четырех системных файлов.</p>
<p>Однако программа HHUPD.EXE поможет только в том случае, если на машине клиента либо вообще нет этих файлов, либо они имеет более старую версию.</p>
<p>Если же эти файлы уже существуют и тем не менее файлы CHM не запускаются из среды Windows, то Вам необходимо будет перенести эти файлы в ручную с той машины, где файлы CHM нормально запускаются и зарегистрировать их вручную при помощи программы Regsvr32.exe примерно так</p>
<pre class="">regsvr32.exe C:\Windows\System32\HHCTRL.OCX</pre>
<p>Следует только помнить, что поскольку речь идет об ActiveX-компонентах их регистрация должна производится в сенасе работы с правами администратора. Это может быть еще одной причиной не работающих файлов справки. Сами файлы OCX были скопированы, но зарегистрировать их не удалось, поскольку установка производилась в сеансе работы не с правами администратора.</p>
<p>При переносе приложения на машину клиента не были установлены дополнительные библиотеки для работы с файлами в CHM-формате</p>
<p>Для работы CHM-файлов в среде FoxPro требуются следующие файлы</p>
<pre class="">
Visual FoxPro 6 FOXHHELPPS.DLL 
FOXHHELP.EXE
Visual FoxPro 7 FOXHHELPPS7.DLL 
FOXHHELP7.EXE
Visual FoxPro 8 FOXHHELPPS8.DLL 
FOXHHELP8.EXE
Visual FoxPro 9 FOXHHELPPS9.DLL 
FOXHHELP9.EXE
При этом регистрация имеет вид</pre>
<pre class="">
regsvr32.exe FOXHHELPPS.DLL 
FOXHHELP.EXE /regserver</pre>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/ne-zapuskaetsya-fajl-pomoshhi-v-chm-formate/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/ne-mogu-izmenit-soderzhimoe-rabochih-tablicz/</link>
					<title><![CDATA[Не могу изменить содержимое рабочих таблиц]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Mon, 31 Oct 2022 10:09:51 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Не могу изменить содержимое рабочих таблиц</h1>
													</header>
													<blockquote>
<p><strong>Проблема</strong>При отладке приложения все нормально. Но при запуске готового файла EXE при любой попытке изменить содержимое любой таблицы появляется сообщение</p>
<pre>Cursor is read-only</pre>
</blockquote>
<p>&nbsp;</p>
<blockquote>
<p><strong>Причина</strong></p>
</blockquote>
<blockquote>
<p>Это надо понимать буквально. Где-то, как-то, Вы изменили статус своих рабочих таблиц таким образом, что они получили статус "Read-Only".</p>
</blockquote>
<p><strong>Решение</strong><br />
Решение зависит от причины, по которой таблицы получили статус Read-Only</p>
<p><strong>Вы включили свои таблицы внутрь проекта</strong></p>
<p>Чтобы убедится в этом, откройте окно вашего проекта и найдите нужную таблицу. Слева от имени таблицы должен стоять значок перечеркнутого кружочка. Если это не так, то щелкните правой кнопкой мыши по имени таблицы и в появившемся меню выберите пункт "Exclude". После этого перекомпилируйте проект (заново постройте EXE).</p>
<p>Включение какого-либо файла внутрь EXE осуществляется аналогично. Правой кнопкой мыши по имени и в открывшемся меню выбрать пункт "Include".</p>
<p>Надо понимать, что включение какого-либо файла внутрь EXE означает, что этот файл становится частью EXE и его модификация недопустима. Это можно использовать как примитивный способ защиты своих данных, если эти данные предоставляются только на чтение.</p>
<p>Соответственно, файл, включенный внутрь EXE не надо поставлять клиенту (он и так находится внутри EXE).</p>
<p><strong>Перенос базы данных клиенту на лазерном диске</strong></p>
<p>Дело в том, что в момент записи на лазерный диск всем файлам автоматически устанавливают признак Read-Only. Соответственно после копирования на жесткий диск у клиента этот признак необходимо снять.</p>
<p>Правой кнопкой мыши в "Проводнике" (Explorer-Windows) на имени файла, в появившемся меню выбрать пункт "Свойства" (Properties) и снять птичку "Только чтение" ("Read-Only"). Если предварительно выделить несколько файлов, то свойства будут распространены на все выделенные файлы.</p>
<p><strong>Настройка прав доступа пользователей</strong></p>
<p>Возможно, папка, в которой расположены файлы DBF администратором была выдана в общее пользование со статусом Read-Only. В этом случае необходимо обратится к администратору с просьбой изменить права доступа.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/ne-mogu-izmenit-soderzhimoe-rabochih-tablicz/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/ne-mogu-vyjti-iz-foxpro-zakryt-prilozhenie/</link>
					<title><![CDATA[НЕ МОГУ ВЫЙТИ ИЗ FOXPRO. ЗАКРЫТЬ ПРИЛОЖЕНИЕ]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Sun, 30 Oct 2022 17:13:39 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>НЕ МОГУ ВЫЙТИ ИЗ FOXPRO. ЗАКРЫТЬ ПРИЛОЖЕНИЕ</h1>
													</header>
													<blockquote>
<p><strong>Проблема</strong><br />
Приложение FoxPro нормально запускается, но когда я хочу из него выйти, например, нажав на "крестик" в правом верхнем углу основного окна, то я получаю сообщение об ошибке</p>
<p><em>Cann't quit Visual FoxPro</em></p>
<p>Или, в старших версиях без сокращений</p>
<p><em>Can not quit Visual FoxPro</em></p>
</blockquote>
<p>Также возможна ситуация, когда приложение FoxPro закрывается, но остается "висеть" в списке запущенных процессов. Т.е. его не видно на панели задач, но можно увидеть в списке процессов (Ctrl+Shift+Esc, закладка "Процессы")</p>
<p><strong>Причина</strong></p>
<p>Скорее всего, Вы забыли прервать режим ожидания событий инициированных пользователем. Т.е. отменить действие команды READ EVENTS</p>
<p><strong>Решение</strong></p>
<p>Перед закрытием приложения надо дать команду</p>
<pre>CLEAR EVENTS</pre>
<p>Если закрытие приложения происходит по нажатию "крестика" в правом верхнем углу основного окна FoxPro, то это событие перехватывается настройкой</p>
<pre>ON SHUTDOWN</pre>
<p>Более подробно этот вопрос рассматривается в статье:</p>
<p><a href="/knowledgebase/glavnyj-startovyj-fajl-proekta/" target="_blank" rel="nofollow noopener"><u>Главный (стартовый) файл проекта</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/ne-mogu-vyjti-iz-foxpro-zakryt-prilozhenie/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/okno-foxpro-melkaet-na-ekrane-i-tut-zhe-zakryvaetsya/</link>
					<title><![CDATA[ОКНО FOXPRO МЕЛЬКАЕТ НА ЭКРАНЕ И ТУТ ЖЕ ЗАКРЫВАЕТСЯ]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Sun, 30 Oct 2022 17:11:50 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>ОКНО FOXPRO МЕЛЬКАЕТ НА ЭКРАНЕ И ТУТ ЖЕ ЗАКРЫВАЕТСЯ</h1>
													</header>
													<blockquote>
<p><b>Проблема</b></p>
<p>При отладке приложения все в порядке. А когда запускаю готовый файл EXE, мое приложение мелькает на экране и тут же закрывается.</p>
<p><b>Причина</b></p>
<p>Скорее всего, Вы забыли сформировать режим ожидания событий, инициированных пользователем. Проще говоря, не указали программе, где она должна остановиться и подождать реакции пользователя. На этапе отладки приложения такой "точкой останова" является ранее запущенная среда FoxPro. Но в готовом приложении этого нет.</p>
</blockquote>
<p><b>Решение</b><br />
Необходимо сформировать режим ожидания событий, инициированных пользователем. Штатным средством для этого является команда</p>
<pre>READ EVENTS</pre>
<p>Более подробно этот вопрос рассматривается в статье:</p>
<p><a href="/knowledgebase/glavnyj-startovyj-fajl-proekta/" target="_blank" rel="nofollow noopener"><u>Главный (стартовый) файл проекта</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/okno-foxpro-melkaet-na-ekrane-i-tut-zhe-zakryvaetsya/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-perenesti-gotovoe-prilozhenie-na-mashinu-klienta/</link>
					<title><![CDATA[Как перенести готовое приложение на машину клиента]]></title>
                    					    <author><![CDATA[Joys]]></author>
                    										    <pubDate>Sun, 30 Oct 2022 17:01:29 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как перенести готовое приложение на машину клиента</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Я написал (а) приложение на FoxPro и создал (а) исполняемый файл EXE. Однако при попытке запуска на машине клиента я получаю сообщение о том, что нет каких-то библиотек. Какие библиотеки он требует? Как правильно установить готовое приложение на машине клиента?</p>
<p><b>Ответ</b></p>
<p>Готовое приложение Visual FoxPro для своей работы требует несколько библиотек поддержки. О некоторых из них, Вы можете узнать непосредственно в HELP для Visual FoxPro в разделе с названием</p>
<p><b>Visual FoxPro Run-Time Libraries</b></p>
<p>Откройте HELP для Visual FoxPro и введите название раздела в кавычках в окно поиска. В этой статье приводится список <u>некоторых</u> библиотек. Более того, не все, приведенные в этом разделе библиотеки действительно нужно переносить на машину клиента.</p>
<p>Поэтому, лучше не играть в "угадайку", копируя файлы поштучно, а создать полноценный дистрибутив Вашего приложения.</p>
<p>До версии Visual FoxPro 6 включительно, для создания дистрибутивов использовался встроенный инструмент. Пункт главного меню Tools - Wizards - Setup. Однако, начиная с версии Visual FoxPro 7, используется внешняя программа, под названием "InstallShield". Эта программа (точнее, ее усеченная версия "Express") поставляется вместе с FoxPro на том же диске.</p>
<p>Если Вы работаете со старой версией FoxPro и используете для создания дистрибутива встроенный Wizard, то следует понимать, что этот Wizard создавался с учетом только тех операционных систем, которые существовали на момент выхода соответствующей версии FoxPro. Это значит, что дистрибутив, созданный таким встроенным Wizard может не установиться на машинах с новейшими операционными системами.</p>
<p>Также почитайте статью на данном сайте:</p>
<p><a href="/knowledgebase/kak-sdelat-exe-fajl/" target="_blank" rel="nofollow noopener"><u>Как сделать exe файл</u></a></p>
<p>В качестве программы для создания инсталляционных пакетов (дистрибутивов) хорошо зарекомендовала себя программа <b>InnoSetup</b>. Вы можете скачать его с данного сайта из раздела "Файловый архив", подраздел "Installer"</p>
<p>Если все-таки решили переносить приложение путем копирования файлов, то список необходимых библиотек и куда их надо класть можно посмотреть здесь</p>
<p><a href="/knowledgebase/vfp-7-runtime-files-vfp-8-runtime-files-vfp-9-runtime-files/"><u>VFP 7 Runtime Files</u></a><br />
<a href="/knowledgebase/vfp-7-runtime-files-vfp-8-runtime-files-vfp-9-runtime-files/"><u>VFP 8 Runtime Files</u></a><br />
<a href="/knowledgebase/vfp-7-runtime-files-vfp-8-runtime-files-vfp-9-runtime-files/"><u>VFP 9 Runtime Files</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="1">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 3 месяца</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=1">Joys</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Joys" href="https://foxclub.ru/account/?user=1">
				<img alt='' src='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/ab07b29cdc9a6e62f794a54e9ccc85af?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 2<i class="rcli fa-file-text-o"></i>Публикации: 177<i class="rcli fa-calendar-check-o"></i>Регистрация: 25-06-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-perenesti-gotovoe-prilozhenie-na-mashinu-klienta/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Установка и запуск готового EXE]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-perevesti-koordinatu-v-pikselyah-pixcels-v-tvipy-twips/</link>
					<title><![CDATA[Как перевести координату в пикселях (Pixcels) в твипы (Twips)]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:35:04 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как перевести координату в пикселях (Pixcels) в твипы (Twips)</h1>
													</header>
													<p><b>Проблема</b></p>
<p>Многие ActiveX компоненты требуют для указания в качестве параметров своих методов координаты в твипах (Twips), но FoxPro дает координаты в пикселах (Pixcels). Как перевести одно в другое?</p>
<p><b>Решение</b></p>
<p>Для того, чтобы каждый раз не пересчитывать коэффициенты заново, создайте свойства nTwipX и nTwipY для хранения переводных коэффициентов по X (по вертикали) и по Y (по горизонтали) соответствеенно.</p>
<p>Тогда следующий код следует выполнить в событии Init того объекта, где созданы эти свойтсва.</p>
<div class="foxcode">
<pre class="bbcode">  
 * Следующие API функции используются для расчета переводного коэффициента    
  DECLARE INTEGER GetActiveWindow IN WIN32API    
  DECLARE INTEGER GetDC IN WIN32API INTEGER iHDC    
  DECLARE INTEGER GetDeviceCaps IN WIN32API INTEGER iHDC, INTEGER iIndex    
        
  LOCAL liHDC    
  liHDC = GetDC(GetActiveWindow())    
  This.nTwipX = 1440/GetDeviceCaps(m.liHDC,88)    
  This.nTwipY = 1440/GetDeviceCaps(m.liHDC,90)    
        
 * Освобождение контекста устройства, для освобождения памяти    
  DECLARE INTEGER ReleaseDC IN WIN32API INTEGER, INTEGER     
  =ReleaseDC(GetActiveWindow(),m.liHDC)</pre>
</div>
<p>
Здесь This.nTwipX и This.nTwipY - это как раз те самые коэффициенты перевода из пикселей в твипы. В данном случае оформлены как дополнительные свойства объекта.</p>
<div class="foxcode">
<pre class="bbcode">  
  Координата_по_Х_в_твипах = This.nTwipX * координата_по_X_в_пикселях   
  Координата_по_Y_в_твипах = This.nTwipY * координата_по_Y_в_пикселях</pre>
</div>
<p>
В большинстве случаев, эти коэффициенты равны 15</p>
<p>Данный код несколько избыточный в части использования функции GetActiveWindow(). Дело в том, что эта функция возвращает, так называемое HWND-окна (некий числовой идентификатор окна).</p>
<p>Но все дело в том, что многие ActiveX имеют свойство, возвращающее значение их HWND, а, начиная с версии Visual FoxPro 7.0, такое свойство имеют и формы собственно FoxPro. Т.е. Вы можете вместо функции GetActiveWindow() напрямую использовать свойство HWND нужного объекта. Впрочем, и в таком виде данный код вполне работоспособен.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-perevesti-koordinatu-v-pikselyah-pixcels-v-tvipy-twips/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[ActiveX]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/na-mashine-klienta-activex-trebuet-liczenziyu/</link>
					<title><![CDATA[На машине клиента ActiveX требует лицензию]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:34:22 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>На машине клиента ActiveX требует лицензию</h1>
													</header>
													<p><b>Проблема.</b></p>
<p>Я использовал в своей программе ActiveX-компонент, а на машине клиента он не работает. Требует какую-то лицензию.</p>
<p><b>Причина.</b></p>
<p>Причина заключается в некоторых юридических тонкостях прав, на использование ActiveX-компонент, реализованных Microsoft. Приблизительно, смысл этих юридических тонкостей можно сформулировать так: нельзя распространять чужой продукт, но можно распространять результат его работы.</p>
<p><b>Решение.</b></p>
<p>Необходимо включить используемый ActiveX-компонент в <u>визуальную</u> библиотеку FoxPro (файл VCX). Такое использование ActiveX-компонентов не считается "распространением чужого продукта" и не требует установку лицензии. На машину клиента необходимо перенести только собственно файл OCX, содержащий этот ActiveX-компонент.</p>
<p>Разумеется, после переноса этот файл OCX необходимо зарегистрировать при помощи программы RegSvr32.exe примерно так</p>
<div class="foxcode">
<pre class="bbcode">regsvr32.exe C:\Windows\System32\Имя_файла.OCX</pre>
</div>
<p>
Здесь вместо текста "Имя_файла" надо написать реальное имя Вашего файла OCX. Файлы OCX, как правило, кладут в директорию System32. Исходя из этого, и написана команда. Но Вы вполне можете положить файл OCX в любое другое место. Соответственно, надо будет подкорректировать команду регистрации.</p>
<p>Любая попытка прямого программного (из файла PRG) создания данного ActiveX-компонента потребует наличия на машине клиента лицензии.</p>
<p>Впрочем, это правило относиться только к тем ActiveX-компонентам, которые созданы собственно Microsoft. Если Вы покупали ActiveX-компонент у стороннего разработчика как отдельный продукт, то Вам следует уточнить у продавца правила распространения программ, использующих данный ActiveX-компонент.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/na-mashine-klienta-activex-trebuet-liczenziyu/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[ActiveX]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-zamenit-soobshhenie-invalid-date-pri-vvode-nekorrektnoj-daty/</link>
					<title><![CDATA[Как заменить сообщение Invalid Date при вводе некорректной даты]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:33:04 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как заменить сообщение Invalid Date при вводе некорректной даты</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Если в TextBox вводится некорректная дата, то появляется сообщение "Invalid Date". Как можно проконтролировать корректность ввода даты до появления этого сообщения и заменить данное сообщение своим?</p>
<p><b>Ответ</b></p>
<p>Для начала следует задуматься о необходимости такой замены. Дело в том, что если Вы поставляете вместе с готовым файлом EXE русскоязычную Run-Time библиотеку с именем vfpXrrus.dll (X - цифра, соответствующая номеру версии Visual FoxPro), то вместо английского сообщения "Invalid Date" возникнет сообщение по-русски "Неверная дата".</p>
<p>Тем не менее, если Вы все-таки хотите произвести подмену вручную, то для этого есть способ.</p>
<p>Начиная с версии Visual FoxPro 5, для объекта TextBox добавлено свойство <b>StrictDataEntry</b>.</p>
<p>По умолчанию, это свойство имеет значение: 1 - Strict. Установите его в значение: 0 - Loose.</p>
<p>В этом случае, если введено некорректное значение даты, то никакого сообщения об ошибке вообще не возникает. Просто значение свойства TextBox.Value становиться пустым.</p>
<p>Это можно определить в событии TextBox.Valid() и выдать собственное сообщение об ошибке</p>
<div class="foxcode">
<pre class="bbcode">  
 * Событие <b>TextBox.Valid</b>  
  IF EMPTY(This.Value) = .T.   
  	MessageBox("Дата введена некорректно!")  
  ENDIF</pre>
</div>
<p>
Однако при таком подходе возникают две проблемы:</p>
<p>1) Событие TextBox.Valid() наступает при выходе из объекта вне зависимости от того, изменяли Вы содержимое данного объекта или нет.</p>
<p>Это значит, что если значение поля изначально было пустым и пользователь в нем ничего не менял, а просто "прошел" через этот объект, например, при помощи клавиши Tab, то возникнет сообщение об ошибке. Чего быть не должно.</p>
<p>2) Если изначально дата уже была введена, а в процессе изменения пользователь ошибся, то желательно установить не пустое значение даты, а вернуть ее в исходное состояние. Т.е. установить то значение, которое было до редактирования.</p>
<p>Чтобы решить эти проблемы необходимо небольшое пояснение.</p>
<p>Если пользователь что-то изменяет в объекте, то на каждую модификацию срабатывает событие TextBox.InteractiveChage(). Но в данном случае недостаточно просто определить факт модификации. Необходимо определить тот факт, что пользователь пытался ввести не пустое значение.</p>
<p>То, что пользователь пытался ввести сохраняется в свойстве TextBox.Text. Точнее, в этом свойстве хранится то, что пользователь видит на экране, а не то, что сохраняется в свойстве TextBox.Value. Хотя значение этих свойств могут и совпадать. Но в общем случае это не так. Они отличаются, например, из-за используемых масок ввода.</p>
<p>К сожалению, нельзя просто сравнить в событии TextBox.Valid() значение свойств TextBox.Value и TextBox.Text. Дело в том, что если объект TextBox имеет не пустое значение свойства TextBox.ControlSource (например, TextBox "привязан" к полю таблицы), то к моменту выполнения события TextBox.Valid() в случае ошибки ввода свойство TextBox.Text также окажется пустым. Отдельное спасибо Андрею Тарасову (<b>XAndy</b>), обратившему на это внимание.</p>
<p>Следовательно, необходимо в событии TextBox.InteractiveChange() организовать сохранение текущего значения свойства TextBox.Text. И если в событии TextBox.Valid() окажется, что значение TextBox.Value пустое, а сохраненное значение TextBox.Text не пустое, то это и будет означать ошибку ввода.</p>
<p>Аналогичным образом следует поступить и для восстановления значения до редактирования. Надо просто сохранить исходное значение. Процедуру сохранения выполнить при входе в объект. Либо в событии TextBox.When(), либо в событии TextBox.GotFocus().</p>
<p>У любого объекта FoxPro есть два дополнительных свойства: <b>Tag</b> и <b>Comment</b>. Это свойства-комментарии. Они никак не влияют на работу объекта и предназначены для хранения справочной информации. Следует только иметь в виду, что они принимают значения только и исключительно символьного типа. Вот эти-то два свойства и используем для хранения нужных значений.</p>
<p>В результате, после всех пояснений, получаем такой код:</p>
<div class="foxcode">
<pre class="bbcode">  
 * Событие <b>TextBox.When</b>  
  This.Comment = DTOC(This.Value)  
    
    
 * Событие <b>TextBox.InteractiveChange</b>  
 * Используется TransForm(), а не DTOC(),   
 * поскольку значение This.Text может не преобразовываться в дату  
  This.Tag = TransForm(This.Text)  
    
    
 * Событие <b>TextBox.Valid</b>  
 * Значение, которое попытался ввести пользователь  
  LOCAL lcUserText  
  lcUserText = This.Tag  
    
 * Очищаем сохраненное значение  
  This.Tag = ""  
    
 * Сравниваю то, что реально введено с тем, что пытались ввести   
 * Предполагаю, что реально введено то, что должно вернуть Ctod(m.lcUserText)  
  If Empty(m.lcUserText)=.F. AND m.lcUserText &lt;&gt; Dtoc(Ctod(m.lcUserText))  
  	This.Value = Ctod(This.Comment)  
  	MessageBox("Неверный ввод даты")  
  	  
 	* Если хотите запретить выход из объекта,   
 	* то снимите комментарий со следующей команды  
 	* Return 0  
  EndIf</pre>
</div>
<p>
Вам решать, стоит ли полученный результат затраченных усилий.</p>
<p><b>Замечание</b></p>
<p>Если объект TextBox, не связан ни с каким источником данных. Т.е. и TextBox.ControlSource, и TextBox.Value при открытии формы не указаны. То для того, чтобы символы разделители в дате не съезжали при вводе, необходимо указать нужный формат</p>
<div class="foxcode">
<pre class="bbcode">TextBox.Format = "D"</pre>
</div>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-zamenit-soobshhenie-invalid-date-pri-vvode-nekorrektnoj-daty/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Controls]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-zastavit-klavishu-s-tochkoj-vsegda-vvodit-tochku/</link>
					<title><![CDATA[Как заставить клавишу с &#8220;точкой&#8221; всегда вводить точку]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:32:26 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как заставить клавишу с &#8220;точкой&#8221; всегда вводить точку</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>На альтернативной цифровой клавиатуре (правая часть клавиатуры под клавишей NumLock) есть клавиша с "точкой". Однако она водит именно точку только при английской раскладке клавиатуры, а при русской раскладке клавиатуры вводит запятую. При вводе чисел с дробной частью это создает проблемы. Как можно заставить вводить символ точки вне зависимости от текущей раскладки клавиатуры?</p>
<p><b>Ответ</b></p>
<p>В событии <b>KeyPress</b> для Вашего объекта TextBox пишете такой код</p>
<div class="foxcode">
<pre class="bbcode">  
  LPARAMETERS nKeyCode, nShiftAltCtrl  
  IF InList(CHR(nKeyCode),'.',',') AND CHR(nKeyCode)&lt;&gt;SET('POINT')  
  	NODEFAULT  
  	DoDefault(ASC(SET('POINT')),nShiftAltCtrl)  
    
 	*!* или вместо DoDefault в данном случае можно дать такую команду  
 	*!* KeyBoard SET('POINT') PLAIN CLEAR  
  ENDIF</pre>
</div>
<p>
Все. Теперь при попытке ввода точки или запятой будет автоматически введен символ, который Вы приняли в качестве разделителя целой и дробной части. Даже если это, например, дефис.</p>
<p>Для удобства работы, лучше создать отдельный класс на основе TextBox с данным кодом, чтобы не дублировать его каждый раз при создании нового объекта.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-zastavit-klavishu-s-tochkoj-vsegda-vvodit-tochku/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Controls]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pri-zapuske-otcheta-iz-formy-formiruyutsya-nevernye-dannye/</link>
					<title><![CDATA[При запуске отчета из формы формируются неверные данные]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:31:02 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>При запуске отчета из формы формируются неверные данные</h1>
													</header>
													<p><b>Проблема:</b></p>
<p>На этапе подготовки и отладки отчета - все нормально, но когда готовый отчет запускается из формы приложения отчет либо выдает сообщения об ошибках, либо формирует некорректные данные.</p>
<p><b>Причина:</b></p>
<p>Отчет это всегда сканирование одной главной таблицы. Для корректной работы отчеты он должен обязательно перейти в рабочую область этой главной таблицы.</p>
<p>Если по каким-либо причинам этого не происходит, то в процессе выполнения отчета он начинает сканировать ту таблицу, которая оказалась в текущей рабочей области. В этом случае результат выполнения отчета становится не предсказуемым.</p>
<p><b>Решение:</b></p>
<p>Способ решения зависит от того, по какой причине оказалась потеряна (не выбрана) главная таблица отчета.</p>
<p>Наиболее вероятными являются следующие причины:</p>
<p></p>
<ol>
<li>В момент вызова отчета фокус находится в объекте Grid</li>
<li>При создании отчета не была явно указана главная таблица отчета</li>
<li>Главная таблица отчета не была открыта или не видна из отчета</li>
</ol>
<p><b>1. В момент вызова отчета фокус находится в объекте Grid.</b></p>
<p>Это BUG (глюк) FoxPro. Причина такого поведения не вполне понятна, но если в момент вызова отчета фокус находится в объекте Grid, то объект Grid "не отпускает" текущую рабочую область.</p>
<p>Решение сводится к тому, чтобы перед выполнением отчета увести фокус с объекта Grid на любой другой объект формы. Если кроме собственно объекта Grid на форме ничего нет, то создайте специальный объект TextBox или CommandButton за границами видимой части окна (Top = -100, Left = -100) и передавайте фокус на этот "невидимый" объект непосредственно перед вызовом отчета:</p>
<div class="foxcode">
<pre class="bbcode">  
  ThisForm.Command1.SetFocus()  
  REPORT FORM MyReport.frx  
  ThisForm.Grid1.SetFocus()</pre>
</div>
<p>
<b>2. При создании отчета не была явно указана главная таблица отчета.</b></p>
<p>Как правило, если Вы используете DataEnvironment отчета, то по-умолчанию главной таблицей отчета становится первая таблица, физически добавленная в DataEnvironment. Однако если по какой-либо причине это не устраивает, то главную таблицу можно указать явно в свойствах собственно DataEnvironment отчета. За это отвечает свойство:</p>
<p>Report.DataEnvironment.InitialSelectedAlias</p>
<p>Это свойство принимает значение алиаса одной из таблиц, добавленных в DataEnvironment собственно отчета. Выбранный алиас и назначается "главной" таблицей отчета.</p>
<p>Если же Вы не используете DataEnvironment отчета, то следует принудительно перейти в рабочую область главной таблицы непосредственно перед вызовом отчета</p>
<div class="foxcode">
<pre class="bbcode">  
  Select MainTab  
  REPORT FORM MyReport.frx</pre>
</div>
<p>
<b>3. Главная таблица отчета не была открыта или не видна из отчета.</b></p>
<p>Подобная ситуация возможна, если Вы не используете DataEnvironment отчета или же установили его свойство</p>
<p>Report.DataEnvironment.AutoOpenTables = .F.</p>
<p>Это означает, что Вы полностью берете на себя ответственность за установку среды окружения отчета на себя. Другими словами, Вам необходимо самостоятельно проверить факт наличия нужных таблиц и открыть их, если это необходимо до того, как отчет начнет выполняться.</p>
<p>Как правило, подобная ситуация возникает, если в качестве источника данных для отчета используется курсор, которого просто не существует как объект, который можно было бы добавить в DataEnvironment отчета.</p>
<p>Но не просто факт использования курсора (это довольно легко определяется), а запуск отчета в Private DataSession. Это настраивается в режиме модификации отчета: пункт меню Report - Private DataSession.</p>
<p>Вообще-то, сама по себе идея запуска отчета в Private DataSession очень хорошая. Работа отчета происходит независимо от работы форм. Но применительно к курсорам следует помнить, что курсор созданный в одной DataSession "не виден" в другой DataSession. А установка свойства Private DataSession, как раз и означает, что отчет будет запущен в "другой" DataSession.</p>
<p>В этом случае формирование курсоров надо перенести извне отчета в методы самого отчета. Как правило, это делается в методах DataEnvironment отчета. Например, в методе</p>
<p>Report.DataEnvironment.BeforeOpenTables</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pri-zapuske-otcheta-iz-formy-formiruyutsya-nevernye-dannye/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Report (Отчеты)]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-zapretit-pechat-iz-okna-predvaritelnogo-prosmotra/</link>
					<title><![CDATA[Как запретить печать из окна предварительного просмотра]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:30:32 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как запретить печать из окна предварительного просмотра</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Как запретить печать из окна предварительного просмотра?</p>
<p><b>Ответ</b></p>
<p>Данная проблема имеет несколько решений, но наиболее корректным является удаление кнопки с изображением принтера из окна предварительного просмотра. Это можно сделать при помощи специально созданного файла ресурсов.</p>
<p>Файл ресурсов, по умолчанию, это файл FoxUser.dbf (fpt). Он хранит настройки всех когда-либо открытых окон в среде FoxPro.</p>
<p>Сначала создадим копию ресурсного файла:</p>
<div class="foxcode">
<pre class="bbcode">  
  SELECT 0  
  USE (SYS(2005)) AGAIN  
  COPY TO NoPrint.dbf  
  USE</pre>
</div>
<p>
В результате получится копия ресурсного файла в текущей директории с именем NoPrint.dbf</p>
<p>Устанавливаем в качестве реусрсного файла этот вновь созданный файл.</p>
<div class="foxcode">
<pre class="bbcode">  
  gcResource=SYS(2005)   &amp;&amp; сохраняю путь к старому ресурсному файлу  
  SET RESOURCE TO NoPrint.dbf</pre>
</div>
<p>
Далее выбираем пункт главного меню View-&gt;ToolBars... Убедитесь, что стоит крестик в пункте "Print Preview" и нажмите кнопку "Customize..."</p>
<p>Теперь нажмите левой кнопкой мыши кнопку с изображеним принтера в ToolBar "Print Preview" и не отпуская перетащите ее за пределы этого ToolBar. Все, кнопка удалена из этого ToolBar и такое состояние сохранено в текущем файле ресурсов.</p>
<p>Восстанавливаем исходный файл ресурсов</p>
<div class="foxcode">
<pre class="bbcode">SET RESOURCE TO (m.gcResource)</pre>
</div>
<p>
Следует заметить, что внутри файла ресурсов много самой разнообразной информации, которая собственно не нужна в данной задаче. Поэтому для экономи места все лишнее можно удалить. Для этого откройте новый файл ресурсов</p>
<div class="foxcode">
<pre class="bbcode">USE NoPrint.dbf</pre>
</div>
<p>
И найдите в нем не удаленную запись со следующими значениями полей:</p>
<div class="foxcode">
<pre class="bbcode">  
  TYPE="PREFW"  
  ID="TTOOLBAR"  
  NAME="Print Preview"</pre>
</div>
<p>
Все остальные записи можно смело удалять. Они никак не влияют на данный ToolBar.</p>
<p>В принципе, этот файл ресурсов (вместе с мемо-полем) можно включить внутрь проекта, чтобы не поставлять отдельно кучу ресурсных файлов.</p>
<p>Собственно запуск отчета с использованием только что созданного файла ресурсов примет вид:</p>
<div class="foxcode">
<pre class="bbcode">  
 * Запоминаю старый файл ресурсов  
  LOCAL lcResource  
  lcResource=SYS(2005)  
 * Подключаю нужный ресурсный файл  
  SET RESOURCE TO NoPrint.dbf  
    
 * Выполняю отчет  
  REPORT FORM MyReport.frx NOCONSOLE PREVIEW  
    
 * Восстанавливаю старый ресурсный файл  
  SET RESOURCE TO (m.lcResource)</pre>
</div>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-zapretit-pechat-iz-okna-predvaritelnogo-prosmotra/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Report (Отчеты)]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-otobrazit-okno-predvaritelnogo-prosmotra-v-as-top-level-forme/</link>
					<title><![CDATA[Как отобразить окно предварительного просмотра в As Top-Level форме]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:29:20 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как отобразить окно предварительного просмотра в As Top-Level форме</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Приложение написано на базе As Top-Level форм. При вызове отчета на предварительный просмотр он вообще не появляется. В чем причина? Как можно отобразить окно предварительного просмотра.</p>
<p><b>Причина</b></p>
<p>Для версий до Visual FoxPro 6 включительно, по умолчанию, окно предварительного просмотра открывается In-Screen. Т.е. внутри основного окна FoxPro.</p>
<p><b>Решение</b></p>
<p>Необходимо перенаправить вывод окна предварительного просмотра в окно, созданное на базе As Top-Level формы. Это стало возможным только с появлением опции IN WINDOW в Visual FoxPro 6.</p>
<p>Пример решения описан в статье Q188887, на сайте Microsoft</p>
<p><a target="_blank" rel="nofollow noopener noreferrer" href="http://support.microsoft.com/kb/q188887/"><u>How to display the Print Preview window in a top-level form in Visual FoxPro</u></a></p>
<p>Суть приведенного там примера заключается в следующем коде</p>
<div class="foxcode">
<pre class="bbcode">  
  oPForm = CREATEOBJECT('printpreview')  
  oPform.visible = .t.    &amp;&amp; Открыть форму в которую пойдет вывод  
 *******  
 * Следующая команда использует опцию IN WINDOW  
 * Заметьте, что использована как опция WINDOW, так и опция IN WINDOW  
 * Опция WINDOW устанавливает для окна предварительного просмотра  
 * те же характеристики, что и у указанного окна, в то время как   
 * опция IN WINDOW говорит о том, внутри какого окна следует открывать  
 * окно предварительного просмотра  
 *******  
  REPORT FORM report_1 PREVIEW WINDOW printpreview IN WINDOW printpreview  
    
 * Класс окна предварительного просмотра  
  DEFINE CLASS printpreview AS form  
    
  ScaleMode = 3  
  Top = 0  
  Left = 0  
  Height = 454  
  Width = 641  
  ShowWindow = 2  
  DoCreate = .T.  
  Caption = "Print Preview Window"  
  Movable = .T.  
  TitleBar = 0  
  WindowState = 0  
  SizeBox = .F.  
  Name = "printpreview"  
    
  ENDDEFINE</pre>
</div>
<p>
Разумеется, Вы можете создать нужный класс в визуальной библиотеке классов. Можете использовать для опции Window одно окно, а для опции IN WINDOW - другое. Это просто пример.</p>
<p><b>Замечание</b></p>
<p>Опция IN WINDOW была добавлена только в версии Visual FoxPro 6. Для младших версий FoxPro придется, так или иначе, использовать основное окно FoxPro.</p>
<p>Т.е. перед открытием окна предварительного просмотра отобразить основное окно FoxPro, а после просмотра - закрыть.</p>
<div class="foxcode">
<pre class="bbcode">  
  _SCREEN.Visible = .T.  
  REPORT FORM MyReport.frx  
  _SCREEN.Visible = .F.</pre>
</div>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-otobrazit-okno-predvaritelnogo-prosmotra-v-as-top-level-forme/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Report (Отчеты)]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-vybrat-printer-iz-okna-predvaritelnogo-prosmotra/</link>
					<title><![CDATA[Как выбрать принтер из окна предварительного просмотра]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:28:34 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как выбрать принтер из окна предварительного просмотра</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>При открытии отчета на предварительный просмотр и последующего нажатия кнопки с изображением принтера не появляется окно настройки принтера. Печать идет на принтер по умолчанию. Как можно вызвать окно настройки принтера из режима предварительного просмотра?</p>
<p><b>Ответ</b></p>
<p>Для предварительного просмотра отчета, как правило, подается команда</p>
<div class="foxcode">
<pre class="bbcode">REPORT FORM MyReport.frx PREVIEW</pre>
</div>
<p>
Отчет будет выдан на экран вместе с командной кнопкой с изображением принтера, по нажатию на которую будет выполнена печать на бумагу.</p>
<p>Однако в этом случае пользователь не получит приглашение по выбору и настройке принтера. Печать пойдет на принтер по умолчанию, и будут использованы его настройки по умолчанию.</p>
<p>Чтобы пользователь получил возможность выбора принтера и его настроек используйте команду</p>
<div class="foxcode">
<pre class="bbcode">REPORT FORM MyReport.frx TO PRINTER PROMPT PREVIEW</pre>
</div>
<p>
Обратите внимание на порядок следования опций. "PREVIEW" должна следовать после опций "TO PRINTER PROMPT". В противном случае, вы получите сообщение об ошибке при попытке выполнить команду.</p>
<p><b>Замечание</b></p>
<p>Этот совет не применим к версиям FoxPro 2.x, а также в том случае, если в команде REPORT FORM используется опция NOWAIT.</p>
<p>Однако в версии Visual FoxPro 9 даже при использовании опции NOWAIT можно вызвать окно предварительной настройки принтера по приведенной выше схеме если предварительно сделать дополнительную настройку</p>
<div class="foxcode">
<pre class="bbcode">  
  SET ReportBehavior 90  
  REPORT FORM MyReport.frx TO PRINTER PROMPT PREVIEW NOWAIT</pre>
</div>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-vybrat-printer-iz-okna-predvaritelnogo-prosmotra/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Report (Отчеты)]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/vfp8-nekorrektno-otobrazhaet-soderzhimoe-otcheta/</link>
					<title><![CDATA[VFP8 некорректно отображает содержимое отчета]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:27:29 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>VFP8 некорректно отображает содержимое отчета</h1>
													</header>
													<p><b>Проблема.</b></p>
<p>При выполнении отчета в среде Visual FoxPro 8.0 буквы наезжают друг на друга или отображаются непонятные "закорючки"</p>
<p><b>Причина.</b></p>
<p>Причина связана с тем, что в Visual FoxPro 8 как-то изменили обработку отчетов, использующих TrueType - шрифты в случае оптимизации печати принтером. Т.е. это ситуации, когда принтер пытается печатать такие шрифты не как графику, а используя некую внутреннюю библиотеку шрифтов.</p>
<p><b>Решение.</b></p>
<p>Есть несколько решений</p>
<ol>
<li>Отказаться от использования TrueType-шрифтов</li>
<li>Изменить настройки драйвера принтера у клиента</li>
<li>Принудительно изменить настройки каждого файла отчета</li>
</ol>
<p><i><u>Отказаться от использования TrueType-шрифтов.</u></i></p>
<p>Данный совет трудно исполним на практике. Как правило, при подготовке отчетов используют несколько видов шрифтов. Сложно найти адекватную замену TrueType-шрифтам.</p>
<p>В идеале, желательно создать собственные шрифты. Но далеко не каждый программист на это способен.</p>
<p>
<i><u>Изменить настройки драйвера принтера у клиента.</u></i></p>
<p>В операционных системах Windows 95 или Windows 98 необходимо установить печать шрифтов в виде графики. Для старших версий операционной системы такого переключателя нет. Там необходимо отключить оптимизацию печати.</p>
<p>Проблема только в том, что это "внешние" по отношению к самой программе настройки. А это значит, что проконтролировать их значение у клиента практически невозможно. Тем более некорректно требовать принудительного задания настроек внешних устройств только для того, чтобы корректно работала одна из многих программ, установленная на компьютере клиента.</p>
<p>
<u><i>Принудительно изменить настройки каждого файла отчета.</i></u></p>
<p>А вот это то, что может реально сделать разработчик программы, хотя это достаточно кропотливое занятие, требующее от программиста повышенной бдительности.</p>
<p>Физически, файлы отчетов FoxPro - это обычные DBF-таблицы. Просто у них изменено расширение. DBF - FRX, FPT - FRT.</p>
<p>Вам следует открыть файл отчета как таблицу командой</p>
<div class="foxcode">
<pre class="bbcode">  
  USE MyReport.frx  
  BROWSE</pre>
</div>
<p>В этой команде следует обязательно указать расширение файла отчета "FRX". В противном случае, FoxPro посчитает, что речь идет о файле с расширением DBF.</p>
<p>Теперь находите в этом файле запись со значениями полей</p>
<div class="foxcode">
<pre class="bbcode">  
  ObjType = 1  
  ObjCode = 53</pre>
</div>
<p>Как правило, это физически самая первая запись.</p>
<p>Откройте на редактирование в этой записи Memo-поле с именем <b>Expr</b>. Найдите (или создайте) строку, начинающуюся с ключевого слова TTOPTION и установите значение</p>
<div class="foxcode">
<pre class="bbcode">TTOPTION=1</pre>
</div>
<p>Это и означает команду принтеру печатать TrueType-шрифты как графику. Сохраните внесенные изменения и закройте файл отчета.</p>
<p>Недостаток данного решения в том, что после каждой модификации отчета при помощи дизайнера отчетов эта настройка опять примет значение 2 или 3. Т.е. после каждой модификации отчетов надо не забыть еще раз открыть файл отчета как таблицу и внести нужные изменения.</p>
<p>Кстати, значение TTOPTION = 2 - это значение по умолчанию, для принтеров Hewlett-Packard использующих Printer Control Language (PCL). Именно поэтому данная проблема чаще всего встречается при работе с принтерами Hewlett-Packard.</p>
<p>
Достаточно подробно данная проблема обсуждалась на этом сайте. Можете почитать дискуссию по приведенной ссылке</p>
<p><a target="_blank" rel="nofollow noopener noreferrer" href="https://forum.foxclub.ru/read.php?f=5&amp;i=69454&amp;t=69454"><u>forum.foxclub.ru</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/vfp8-nekorrektno-otobrazhaet-soderzhimoe-otcheta/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Report (Отчеты)]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/neustranimaya-oshibka-pri-vypolnenii-otcheta/</link>
					<title><![CDATA[Неустранимая ошибка при выполнении отчета]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 08:20:27 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Неустранимая ошибка при выполнении отчета</h1>
													</header>
													<p><b>Проблема</b></p>
<p>При работе в Visual FoxPro 5.0 или Visual FoxPro 6.0 запуск на выполнение готового отчета приводит к неустранимой ошибке и прерыванию выполнения приложения. Как правило, это происходит в операционных системах Windows 95 или Windows 98. Хотя для версии Visual FoxPro 5.0 это может произойти на любой операционной системе.</p>
<p><b>Причина</b></p>
<p>Причина заключается в конфликте использования сопроцессора собственно FoxPro и текущим драйвером принтера.</p>
<p><b>Решение</b></p>
<p>Решение заключается либо в отключении сопроцессора (это можно сделать через панель управления), либо в принудительной его очистке при помощи специальной библиотеки</p>
<pre class="bbcode">  
  DECLARE _fpreset IN msvcrt20.dll  
  =_fpreset()  
 * Запуск на выполнение отчета  
  REPORT FORM MyReport.frx  
  =_fpreset()</pre>
<p>
Подробнее об этой ошибке можно прочитать в базе знаний на сайте MicroSoft. Статья Q183522</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/neustranimaya-oshibka-pri-vypolnenii-otcheta/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Report (Отчеты)]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-iz-modalnoj-formy-otkrytoj-cherez-show1-vernut-znachenie/</link>
					<title><![CDATA[Как из модальной формы, открытой через Show(1) вернуть значение]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 28 Oct 2020 06:52:09 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как из модальной формы, открытой через Show(1) вернуть значение</h1>
													</header>
													<p><b>Вопрос</b>:</p>
<p>Я создал класс формы и создаю экземпляр модальной формы командой</p>
<pre class="bbcode">  
  LOCAL loForm  
  loForm = CreateObject("MyFormClass")  
  m.loForm.Show(1)</pre>
<p>Как из такой формы вернуть значение?</p>
<p><b>Ответ</b>:</p>
<p>Идея решения принадлежит Вадиму Пирожкову (Piva).</p>
<p>Суть решения сводится к тому, что форма не может быть уничтожена, пока существует хотя бы одна ссылка на эту форму. Эта дополнительная ссылка создается при помощи объектных скобок WITH...ENDWITH.</p>
<p>Создание экземпляра такой формы примет вид:</p>
<pre class="bbcode">  
  LOCAL loForm, lvProp1, lvProp2  
  loForm = CreateObject("MyFormClass")  
  WITH m.loForm  
  	.Show(1)  
  	m.lvProp1 = .Text1.Value  
  	m.lvProp2 = .Prop2  
  ENDWITH</pre>
<p>Здесь Text1 – это объект, расположенный на форме, а Prop2 – свойство самой формы.</p>
<p>До тех пор, пока не будет закрыта объектная скобка "ENDWITH" форма не может быть удалена. Следовательно, будут доступны для прямого чтения все ее свойства и методы.</p>
<p>Но если форма не может быть удалена, то прямая команда ThisForm.Release() будет проигнорирована или же ее выполнение приведет к различным глюкам.</p>
<p>Чтобы все-таки удалить форму используется другая особенность модальных форм в FoxPro.</p>
<p>Модальной может быть только видимая форма. Как только модальная форма перестает быть видимой, она перестает быть модальной.</p>
<p>Другими словами, закрытие формы осуществляется не одной, а двумя командами:</p>
<pre class="bbcode">  
  ThisForm.Hide()  
  ThisForm.Release()</pre>
<p><b>Замечание</b>:</p>
<p>В принципе, можно обойтись и без дополнительной объектной переменной для вызова формы. Примерно так:</p>
<pre class="bbcode">  
  LOCAL lvProp1, lvProp2  
  WITH CreateObject("MyFormClass")  
  	.Show(1)  
  	m.lvProp1 = .Text1.Value  
  	m.lvProp2 = .Prop2  
  ENDWITH</pre>
<p>Это как Вам покажется удобнее. Надо только не забыть присвоить "внешним" (по отношению к объектной скобке WITH...ENDWITH) переменным значения свойств модальной формы.</p>
<p>Темы, связанные с данной:</p>
<p><a target="_blank" rel="nofollow noopener noreferrer" href="https://forum.foxclub.ru/read.php?32,177177,177218#msg-177218"><u>Что означает префикс (буква) "m." перед именем</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-iz-modalnoj-formy-otkrytoj-cherez-show1-vernut-znachenie/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Form]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-iz-modalnoj-formy-vernut-neskolko-znachenij/</link>
					<title><![CDATA[Как из модальной формы вернуть несколько значений]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Tue, 20 Oct 2020 05:36:19 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как из модальной формы вернуть несколько значений</h1>
													</header>
													<blockquote><p><b>Вопрос</b>:Запускаю модальную форму командой:</p>
<pre class="bbcode">DO FORM MyForm.scx TO m.MyVar</pre>
<p>В переменную m.MyVar будет записано одно возвращаемое значение. А как вернуть из модальной формы несколько значений? Как вернуть из модальной формы массив?</p></blockquote>
<p><b>Ответ</b>:</p>
<p>Идея решения принадлежит Юрию Шутенко (JS).</p>
<p>Суть идеи заключается в том, что хотя FoxPro ограничивается одним возвращаемым значением, но не накладывается никаких ограничений на тип этого возвращаемого значения. В данном случае, следует в качестве возвращаемого значения воспользоваться переменной типа "Object".</p>
<p>В событии UNLOAD формы пишется примерно такой код:</p>
<p></p>
<pre class="bbcode">  
 * Создаем переменную типа "Object"  
  LOCAL loReturnValue   
  loReturnValue = CreateObject("Empty")  
    
 * Формируем в этой переменной нужное количество свойств  
 * и записываем в них нужные значения  
  AddProperty(m.loReturnValue,"Prop1")  
  m.loReturnValue.Prop1 = "Первое значение"  
    
  AddProperty(m.loReturnValue,"Prop2")  
  m.loReturnValue.Prop2 = "Второе значение"  
    
 * Добавляем свойство типа "массив"  
  AddProperty(m.loReturnValue,"PropArray[2,2]")  
  m.loReturnValue.PropArray[1,1] = 1  
  m.loReturnValue.PropArray[1,2] = 2  
  m.loReturnValue.PropArray[2,1] = 3  
  m.loReturnValue.PropArray[2,2] = 4  
    
  RETURN m.loReturnValue</pre>
<p>
Вызов такой формы и разбор возвращаемых параметров примет такой вид</p>
<pre class="bbcode">  
  LOCAL loNewValue  
  loNewValue = NULL  
    
  DO FORM MyForm.scx TO m.loNewValue  
    
 * Переписываем возвращенные значения из свойств объекта в переменные памяти  
  LOCAL lcVal1, lcVal2, laArray(2,2)  
  lcVal1 = m.loNewValue.Prop1  
  lcVal2 = m.loNewValue.Prop2  
  =ACOPY(m.loNewValue.PropArray, m.laArray)</pre>
<p>
Впрочем, можно и не переписывать значений из свойств полученного объекта в переменные памяти. Это уже зависит от конкретной задачи.</p>
<p><b>Замечание</b>:</p>
<p>Объект класса "Empty" и функция AddProperty() были введены в FoxPro в версии Visual FoxPro 8. Для младших версий FoxPro в качестве возвращаемого объекта можно использовать объект класса "Custom", а для создания новых свойств его метод Custom.AdProperty().</p>
<pre class="bbcode">  
 * Создаем переменную типа "Object"  
  LOCAL loReturnValue   
  loReturnValue = CreateObject("Custom")  
    
 * Формируем в этой переменной нужное количество свойств  
 * и записываем в них нужные значения  
  m.loReturnValue.AddProperty("Prop1")  
  m.loReturnValue.Prop1 = "Первое значение"  
    
  ...</pre>
<p>Метод AddProperty() был введен в FoxPro в версии Visual FoxPro 6. Для младших версий FoxPro нужное количество свойств возвращаемого объекта, да и сам объект, необходимо сформировать заранее в соответствующей библиотеке классов.</p>
<p>
Темы, связанные с данной:</p>
<p><a target="_blank" rel="nofollow noopener noreferrer" href="https://forum.foxclub.ru/read.php?32,177177,177218#msg-177218"><u>Что означает префикс (буква) "m." перед именем</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-iz-modalnoj-formy-vernut-neskolko-znachenij/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Form]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pochemu-parametry-peredannye-v-formu-vidno-tolko-v-init-formy/</link>
					<title><![CDATA[Почему параметры, переданные в форму &#8220;видно&#8221; только в INIT-формы]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 13:08:30 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Почему параметры, переданные в форму &#8220;видно&#8221; только в INIT-формы</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
Я передаю параметры в форму. Они принимаются в событии INIT-формы и там они имеют переданные значения. Почему эти же переданные значения не "видно" из других методов формы?</p></blockquote>
<p><b>Ответ</b></p>
<p>Дело в том, что параметр - это переменная памяти. Как и любая другая переменная памяти, она имеет область видимости. Если параметры принимаются через команду <em>PARAMETERS</em>, то область видимости <em>PRIVATE</em>. А если через команду <em>LPARAMETR</em>S, то область видимости <em>LOCAL</em>.</p>
<p>Кроме того, следует учитывать тот факт, что даже события, выполняющиеся при инициализации формы, выполняются не друг <strong>ИЗ</strong> друга, а друг <strong>ЗА</strong> другом. Т.е. это не вложенные друг в друга процедуры, а последовательность процедур.</p>
<p>Следовательно, в общем случае, даже переменная с областью видимости PRIVATE, объявленная в одном из событий или методов формы, не будет "видна", ни в каком другом событии или методе формы.</p>
<p>Чтобы обойти это ограничение, следует в том же событии INIT-формы присвоить переданные через параметры значения специально созданным свойствам (properties) формы. Как это сделать, подробно описано здесь</p>
<p><a href="http://forum.foxclub.ru/read.php?f=32&amp;i=45&amp;t=26" target="_blank" rel="nofollow noopener noreferrer"><u>Почему созданный массив или переменную не "видно" в других методах формы</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pochemu-parametry-peredannye-v-formu-vidno-tolko-v-init-formy/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Form]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-perehvatit-nazhatie-na-krestik-v-pravom-verhnem-uglu-formy/</link>
					<title><![CDATA[Как перехватить нажатие на крестик в правом верхнем углу формы]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:46:06 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как перехватить нажатие на крестик в правом верхнем углу формы</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Как перехватить нажатие на крестик в правом верхнем углу формы?</p>
<p><b>Ответ</b></p>
<p>При нажатии на крестик в правом верхнем углу формы срабатывает событие формы QueryUnload(). Если в этом событии дать команду</p>
<div class="foxcode">
<pre class="bbcode">NODEFAULT</pre>
</div>
<p>то закрытие формы будет отменено. Т.е. можно попросить пользователя подтвердить желание закрыть форму.</p>
<div class="foxcode">
<pre class="bbcode">*** Событие формы QueryUnload  
  IF MessageBox("Вы действительно хотите закрыть форму",4+32+256,"Закрытие формы")=7  
 	* Нажали кнопку "Нет"  
  	NODEFAULT  
  ENDIF</pre>
</div>
<p>Если у Вас на форме предусмотрена специальная кнопка "Выход", по нажатию на которую происходит закрытие формы, то, для того, чтобы не дублировать один и тот же код в несколких местах просто делайте вызов события нажатия данной кнопки при нажатии на крестик. Примерно так:</p>
<div class="foxcode">
<pre class="bbcode">*** Событие формы QueryUnload  
  NODEFAULT  
  ThisForm.CmdExit.Click()</pre>
</div>
<p>Здесь CmdExit - это имя кнопки "Выход".</p>
<p>Следует иметь в виду, что при вызове метода Release() или использовании команды RELEASE для закрытия формы событие QueryUnload() будет проигнорировано. Т.е. не сработает.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-perehvatit-nazhatie-na-krestik-v-pravom-verhnem-uglu-formy/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Form]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pochemu-sozdannyj-massiv-ili-peremennuyu-ne-vidno-v-drugih-metodah-formy/</link>
					<title><![CDATA[Почему созданный массив или переменную не &#8220;видно&#8221; в других методах формы]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:45:26 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Почему созданный массив или переменную не &#8220;видно&#8221; в других методах формы</h1>
													</header>
													<p><b>Проблема</b></p>
<p>В одном из методов формы или одного из ее объектов я создаю массив или переменную. Почему я не могу использовать этот массив или переменную в других методах и событиях, как самой формы, так и ее объектов. Например, как источник данных для ComboBox.</p>
<p><b>Причина</b></p>
<p>По умолчанию, если область видимости переменной памяти или массива не указана явно через команды PUBLIC, PRIVATE или LOCAL, то для такой переменной памяти или массива устанавливается область видимости PRIVATE. Т.е. команда DIMENSION (DECLARE) создаст массив с областью видимости PRIVATE.</p>
<p>Это значит, что созданный в методе формы или одного из ее объектов массив будет автоматически уничтожен по завершении того метода, в котором этот массив был создан.</p>
<p><b>Решение</b></p>
<p>Есть два принципиальных способа решения</p>
<ol>
<li>Установить область видимости массива PUBLIC</li>
<li>Создать дополнительное свойство (Property) типа массив</li>
</ol>
<p>По ряду причин, назначение <u>локальному</u> объекту области видимости PUBLIC - это не очень хорошая идея. В данном случае, под "локальным объектом" подразумевается массив, поскольку он нужен "локально", в пределах одной формы.</p>
<p>Наилучшим решением будет создание дополнительного свойства (Property) типа массив. Такое свойство можно создать как программно, используя метод AddProperty(), так и в дизайнере формы через пункт меню "Form", подпункт "New Property" или "Edit Property/Method".</p>
<p>Признаком того, что данное свойство является массивом, служит указание размерности. Например:</p>
<div class="foxcode">
<pre class="bbcode">ThisForm.AddProperty("aArray[1,1]")</pre>
</div>
<p>Размерность такого массива впоследствии можно изменять программно, через команду Dimension. Например:</p>
<div class="foxcode">
<pre class="bbcode">DIMENSION ThisForm.aArray(10,2)</pre>
</div>
<p>Теперь Вы можете из любого объекта формы обратиться к данному массиву, поскольку он является неотъемлемой частью самой формы.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pochemu-sozdannyj-massiv-ili-peremennuyu-ne-vidno-v-drugih-metodah-formy/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Form]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/v-gotovom-exe-vse-menyu-ili-ego-chast-otobrazhaetsya-ne-po-russki/</link>
					<title><![CDATA[В готовом EXE все меню или его часть отображается не по русски]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:25:06 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>В готовом EXE все меню или его часть отображается не по русски</h1>
													</header>
													<p><b>Проблема</b></p>
<p>При переносе готового приложения на машину клиента все меню или его часть отображается не по русски или непонятными закорючками.</p>
<p><b>Причина</b></p>
<p>Причин данной проблемы может быть несколько. Но наиболее вероятная - это изменение тем рабочего стола. Точнее, не был указан вообще, или указан какой-либо специфический шрифт для отображения меню.</p>
<p><b>Решение</b></p>
<p>Установите корректный шрифт меню для используемой темы рабочего стола. Обычно это шрифт Tahoma, 8. Или просто установите какую-либо стандартную тему рабочего стола со шрифтами по умолчанию.</p>
<p>К сожалению, решить данную проблему программно (т.е. явно указать шрифт для меню) можно лишь частично. Можно задать шрифт для выпадающих пунктов меню, но основная линейка меню использует только и исключительно системные настройки. Как это можно сделать посмотрите здесь</p>
<p><a href="http://forum.foxclub.ru/read.php?32,177181,177255#msg-177255" target="_blank" rel="nofollow noopener noreferrer"><u>Как изменить шрифт пунктов меню в дизайнере меню</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/v-gotovom-exe-vse-menyu-ili-ego-chast-otobrazhaetsya-ne-po-russki/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Menu]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-izmenit-shrift-punktov-menyu-v-dizajnere-menyu/</link>
					<title><![CDATA[Как изменить шрифт пунктов меню в дизайнере меню]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:24:25 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как изменить шрифт пунктов меню в дизайнере меню</h1>
													</header>
													<p><b>Вопрос:</b></p>
<p>Как изменить шрифт пунктов меню в дизайнере меню?</p>
<p><b>Ответ:</b></p>
<p>Непосредственно в дизайнере меню такого пункта нет.</p>
<p>Вероятно, причина в том, что настройки основной линейки меню берутся из системных настроек (из настроек Windows). Т.е. даже если Вы явно укажите свой шрифт для пунктов основной линейки меню, то они будут проигнорированы. Вот разработчики FoxPro и посчитали, что нет смысла вводить настройку, которая все равно игнорируется в основной линейке меню.</p>
<p>Однако для всех прочих пунктов меню все-таки можно явно указать шрифт.</p>
<p>Дело в том, что, то, что формируется в дизайнере меню - это не окончательное меню, а лишь некий "макет" меню. Из этого макета впоследствии формируется окончательное меню, когда Вы выбираете пункт системного меню Menu - Generate. Эта генерация выполняется несколько формально. Чем, в данном случае, и следует воспользоваться.</p>
<p>Выберите нужный Вам пункт меню (исключая пункт основной линейки меню) и нажмите кнопку в столбце "Options".</p>
<p>В разделе SKIP FOR напишите примерно следующее:</p>
<div class="foxcode">
<pre class="bbcode">.F. FONT "Arial Cyr",20 STYLE "B"</pre>
</div>
<p>После генерации меню получим в итоговом файле MPR что-то вроде</p>
<div class="foxcode">
<pre class="bbcode">  
  DEFINE BAR 1 OF пример PROMPT "Пример" ;  
  SKIP FOR .F. "Arial Cyr",20 STYLE "B"</pre>
</div>
<p>В режиме Preview в самом дизайнере меню Вы не увидите результатов этого "хакерского" трюка. Результат будет виден только при запуске самого меню.</p>
<p>Если по каким-либо причинам, Вы не хотите использовать раздел <b>SKIP FOR </b>для указания шрифта, то примерно, то же самое можно сделать в разделе <b>Message</b>. Только там код будет несколько другим</p>
<div class="foxcode">
<pre class="bbcode">'' FONT "Arial Cyr",20 STYLE "B"</pre>
</div>
<p>После генерации меню получим в итоговом файле MPR что-то вроде</p>
<div class="foxcode">
<pre class="bbcode">  
  DEFINE BAR 1 OF пример PROMPT "Пример" ;  
  MESSAGE '' "Arial Cyr",20 STYLE "B"</pre>
</div>
<p>Разумеется, для задания шрифта следует использовать только один раздел. Т.е. либо раздел <b>SKIP FOR</b>, либо раздел <b>Message</b>. Не надо указывать шрифт в обоих разделах. Это вызовет синтаксическую ошибку в итоговом меню. Будет одновременно две опции FONT у одного пункта.</p>
<p><b>Замечание:</b></p>
<p>Начиная с версии Visual FoxPro 9, в синтаксисе команды DEFINE BAR у опции FONT появился третий необязательный параметр - nFontCharSet. Т.е. можно сделать шрифт меню относительно независимым от региональных настроек системы. Например, для русского языка в разделе SKIP FOR это будет выглядеть примерно так:</p>
<div class="foxcode">
<pre class="bbcode">.F. FONT "Arial",20,204 STYLE "B"</pre>
</div>
<p>Более того, генератор меню версии Visual FoxPro 9 стал более "интеллектуальным". Если у него получается конструкция вида SKIP FOR .F., то она просто исключается, и меню будет иметь следующий вид</p>
<div class="foxcode">
<pre class="bbcode">  
  DEFINE BAR 1 OF пример PROMPT "Пример" ;  
  "Arial",20,204 STYLE "B"</pre>
</div>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-izmenit-shrift-punktov-menyu-v-dizajnere-menyu/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Menu]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pochemu-v-gotovom-exe-ne-rabotaet-kopirovanie-po-ctrl-c-ctrl-v/</link>
					<title><![CDATA[Почему в готовом EXE не работает копирование по Ctrl+C, Ctrl+V]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:23:34 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Почему в готовом EXE не работает копирование по Ctrl+C, Ctrl+V</h1>
													</header>
													<p><b>Проблема</b></p>
<p>На этапе разработки приложения работало копирование через буфер обмена (горячие клавиши Ctrl+C, Ctrl+V), но в готовом файле EXE эти комбинации клавиш не работают. Как можно исправить эту ситуацию?</p>
<p><b>Причина</b></p>
<p>Эти комбинации горячих клавиш связаны с определенными пунктами системного меню. Если в Вашем приложении не предусмотрены данные пункты меню, то и не будет выполнено никаких действий для указанных комбинаций клавиш. Просто не указано, что именно должно выполняться.</p>
<p><b>Решение</b></p>
<p>Вам необходимо определить соответствующие пункты меню. Это все те пункты, которые определены в выпадающем меню для пункта системного меню Edit. Обычно этот пункт делается вторым пунктом основной линейки меню. Т.е. в Вашем файле для запуска основного меню должно быть примерно следующий код.</p>
<div class="foxcode">
<pre class="bbcode">  
 * Первый пункт основной линейки меню  
  DEFINE PAD _msm_edit OF _MSYSMENU PROMPT "Правка" COLOR SCHEME 3  
 * Прочие пункты основной линейки меню  
    
  DEFINE POPUP _medit MARGIN RELATIVE SHADOW COLOR SCHEME 4  
  DEFINE BAR _MED_UNDO OF _medit PROMPT "Отменить" ;  
  	KEY CTRL+Z, "CTRL+Z"  
  DEFINE BAR _MED_REDO OF _medit PROMPT "Вернуть" ;  
  	KEY CTRL+R, "CTRL+R"  
  DEFINE BAR _MED_SP100 OF _medit PROMPT "\-"  
  DEFINE BAR _MED_CUT OF _medit PROMPT "Вырезать" ;  
  	KEY CTRL+X, "CTRL+X"  
  DEFINE BAR _MED_COPY OF _medit PROMPT "Копировать" ;  
  	KEY CTRL+C, "CTRL+C"  
  DEFINE BAR _MED_PASTE OF _medit PROMPT "Вставить" ;  
  	KEY CTRL+V, "CTRL+V"  
  DEFINE BAR _MED_CLEAR OF _medit PROMPT "Очистить"  
  DEFINE BAR _MED_SP200 OF _medit PROMPT "\-"  
  DEFINE BAR _MED_SLCTA OF _medit PROMPT "Выделить все" ;  
  	KEY CTRL+A, "CTRL+A"</pre>
</div>
<p>Если Вы делаете свое меню, используя, дизайнер меню, то</p>
<ul>
<li>Присвоение имени "_msm_edit" производится в окне, которое появляется при нажатии кнопки в столбце "Options" напротив пункта меню "Правка"</li>
<li>Для присвоения имени выпадающего Popup-меню "_medit" в дизайнере меню войдите в подменю "Правка". Далее выберите пункт системного меню View, подпункт Menu Options и в графе Name впишите значение "_medit" (без кавычек, разумеется)</li>
<li>Для присвоения имен BAR-пунктам выберите в столбце Result дизайнера меню значение "Bar #" и впишите соответствующие имена в столбце для ввода команд</li>
<li>Комбинации горячих клавиш назначаются в окне, которое появляется при нажатии кнопки в столбце "Options" напротив соответствующего Bar-пункта меню
<p>Следует заметить, что для функционирования комбинаций горячих клавиш вовсе не обязательно активировать ранее определенное меню. Достаточно самого факта его определения.</p>
<p>Впрочем, я бы рекомендовал все-таки его сделать, поскольку сам Pad-пункт главной линейки меню "_msm_edit" - это хорошая "привязка" для динамического добавления "контекстного" меню. Т.е. такого пункта меню, которое появляется только при активации определенных форм.</li>
</ul>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pochemu-v-gotovom-exe-ne-rabotaet-kopirovanie-po-ctrl-c-ctrl-v/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Menu]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-dobavit-v-menyu-spisok-otkrytyh-okon/</link>
					<title><![CDATA[Как добавить в меню список открытых окон]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:22:29 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как добавить в меню список открытых окон</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Как добавить в меню список всех открытых окон</p>
<p><b>Ответ</b></p>
<ul>
<li>В главной линейке меню создаем пункт "Окна"</li>
<li>В этом пункте меню нажимаем кнопку в столбце "Options"</li>
<li>В открывшемся окне вводим Pad Name = _msm_windo</li>
<li>У пункта меню "Окна", оставляем столбец "Result" в значении "SubMenu" и нажимаем кнопку "Edit" для создания подменю</li>
<li>Необходимо создать в подменю хотя бы один пункт. Например, пункт "Следующее окно", в разделе Result = #Bar, а в качестве значения _MWI_ROTAT</li>
<li>Теперь выбираем пункт основного меню FoxPro с именем View, подпункт Menu Options</li>
<li>Вводим значение Name = _MWINDOW
<p>Все. Теперь в раскрывающемся меню "Окна" будет отображаться список ВСЕХ созданных окон. Даже если это окно не отображается на экране (скрыто).</p>
<p>Для проверки, дайте в командном окне команду</p>
<p>DEFINE WINDOW test FROM 0,0 to 10,10</p>
<p>Окно не активно. Только создано. Тем не менее, уже отображается в списке окон пункта Window. Более того, на него можно переключиться!</p>
<p>Следует помнить, что при редактировании меню в дизайнере, имя выпадающего Popup-меню автоматически устанавливается равным имени PAD-пункта из которого оно собственно "выпадает". Это значит, что если по каким-либо причинам Вы измените название PAD-пункта. Например, вместо "Окна" напишите "Окно", то имя POPUP-меню автоматически измениться на "Окно". Надо будет не забыть, снова исправить его на _MWINDOW</p>
<p>Если Вас не устраивает отображение вообще всех открытых окон, то в этом случае Вам придется самостоятельно вести этот список и формировать выпадающее меню динамически.</li>
</ul>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-dobavit-v-menyu-spisok-otkrytyh-okon/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Menu]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pri-zapuske-menyu-poyavlyaetsya-soobshhenie-o-sintaksicheskoj-oshibke/</link>
					<title><![CDATA[При запуске меню появляется сообщение о синтаксической ошибке]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:21:51 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>При запуске меню появляется сообщение о синтаксической ошибке</h1>
													</header>
													<blockquote><p><b>Проблема</b><br />
Создаю меню в дизайнере меню. Но при запуске меню на исполнение появляется сообщение о синтаксической ошибке. Если его проигнорировать, то дальнейшая работа происходит без ошибок.</p></blockquote>
<p><b>Причина</b></p>
<p>Проблема связана с некорректной интерпретацией русских букв в качестве "горячих клавиш" в основной линейке меню.</p>
<p>"Горячая клавиша" - это клавиша или набор клавиш, нажатие на которые вызывает выполнение соответствующего пункта меню без необходимости выбора его мышкой.</p>
<p>Дело в том, что если, для пункта <u>в основной</u> линейке меню явно не указана "горячая клавиша", то по умолчанию, штатным генератором меню в качестве "горячей клавиши" назначается комбинация клавиши Alt и первого символа названия пункта меню. Как правило, это русская буква. В результате, генератор меню создает команду вида</p>
<div class="foxcode">
<pre class="bbcode">DEFINE PAD _1h610hbkn OF _MSYSMENU PROMPT "Пример" COLOR SCHEME 3 ;  
  	KEY ALT+П, ""</pre>
</div>
<p>Вот в момент выполнения подобной команды и возникает сообщение о синтаксической ошибке на фрагменте "KEY ALT+П". Игнорирование этой ошибки приводит к тому, что на данный пункт меню просто не назначается горячая клавиша. Хотя сам пункт меню успешно создается.</p>
<p><b>Решение</b></p>
<p>Решение заключается в том, чтобы для всех пунктов основной линейки меню принудительно назначать горячие клавиши. Например, русской букве "П" соответствует латинская буква "G" (одна и та же клавиша). Вот и следует назначить для PAD-пункта "Пример" горячую клавишу "Alt+G".</p>
<p>Правда, возможно и другое решение.</p>
<p>За генерацию меню отвечает специальная программа Genmenu.prg Ее можно отредактировать, для того, чтобы подавить автоматическую генерацию горячих клавиш, если они не были заданы явно. Для этого вызываете данную программу на редактирование:</p>
<div class="foxcode">
<pre class="bbcode">MODIFY COMMAND (Home()+"genmenu.prg")</pre>
</div>
<p>За добавление горячих клавиш отвечает функция AddKey. Перейдите к этой функции на команду</p>
<div class="foxcode">
<pre class="bbcode">FUNCTION addkey</pre>
</div>
<p>и закомментируйте в этой функции весь условный оператор, начинающийся с фразы:</p>
<div class="foxcode">
<pre class="bbcode">IF !IsLeadByte(prompt)</pre>
</div>
<p>Однако оставьте не закомментированной в нем единственную строчку</p>
<div class="foxcode">
<pre class="bbcode">STORE "" to m.cKeyname</pre>
</div>
<p>Т.е. соответствующий кусок программы должен выглядеть так:</p>
<div class="foxcode">
<pre class="bbcode">*!* IF !IsLeadByte(prompt)   
 *!* STORE c_key_padhotkey_LOC + UPPER(LEFT(prompt,1)) TO m.cKeyname   
 *!* ELSE   
  STORE "" to m.cKeyname   
 *!* ENDIF</pre>
</div>
<p>Сохраните и откомпилируйте измененный файл GenMenu.prg.</p>
<p>Все. Теперь Вам остается только повторить генерацию всех ранее созданных меню. Сообщение о синтаксической ошибке больше возникать не будут.</p>
<p>О других способах решения данной проблемы можно почитать здесь</p>
<p><a href="http://www.foxclub.ru/sol/index.php?act=view&amp;id=138" target="_blank" rel="nofollow noopener noreferrer"><u>Устранение сообщения о синтаксической ошибке при запуске меню</u></a></p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pri-zapuske-menyu-poyavlyaetsya-soobshhenie-o-sintaksicheskoj-oshibke/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Menu]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-zapolnit-tabliczu-v-ms-word/</link>
					<title><![CDATA[Как заполнить таблицу в MS Word]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:19:46 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как заполнить таблицу в MS Word</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
Как заполнить таблицу в документе MS Word данными из таблицы FoxPro?</p></blockquote>
<p><b>Ответ</b></p>
<p>Прежде всего, следует серьезно обдумать возможность использования вместо прграммы MS Word для отображения табличных данных программы MS Excel. Поскольку именно эта программа предназначена для заполнения табличных данных. Для MS Word таблица – это вспомогательный элемент.</p>
<p>Впрочем, заполнение таблицы MS Word, в своей основе, мало отличается от заполнения таблицы в MS Excel. Точно также происходит адресация к конкретной ячейке с последующим изменением одного из свойств этой ячейки. Сложность заключается именно в способе адресации.</p>
<p>Адресацию к объектам MS Word можно сравнить с адресацией к объектам формы в FoxPro. Вы ведь можете положить объект TextBox как собственно на форму, так и на закладку PageFrame или внутрь объекта контейнера. Соответственно, изменится и способ адресации к объекту. Надо будет указать в иерархии все те объекты-контейнеры, внутри которых расположен нужный Вам объект.</p>
<p>Правда, MS Word имеет и другое отличие от объектов FoxPro. Как правило, Вы обращаетесь к объектам формы в FoxPro по их именам. Объекты MS Word, как правило, собственных имен не имеют. Все объекты MS Word являются членами тех или иных коллекций и обращение к ним происходит по их индексам внутри соответствующих коллекций.</p>
<p>Следовательно, в общем случае, адресация к таблице в MS Word будет иметь вид</p>
<p><i>Приложение_Word.Коллекция_Документов(Индекс_Документа).Коллекция_Таблиц(Индекс_Таблицы)</i></p>
<p>Но это только в том случае, если таблица лежит непосредственно на листе документа. Если же она вложена в другой объект, то между "Коллекцией_Документов" и "Коллекцией_Таблиц" необходимо добавить коллекцию объекта-контейнера.</p>
<p>Существенным недостатком такого способа адресации является невольная привязка к физическому порядку добавления объектов в документ MS Word. Например, если Вы добавили нужную Вам таблицу физически самой первой, то она, естественно, будет самой первой в коллекции таблиц. Но если Вы в процессе модификации шаблона документа вырежете Вашу таблицу, создадите новую таблицу, а потом восстановите старую таблицу, то она окажется уже второй в коллекции таблиц. Эту особенность следует помнить при написании программ заполнения таблиц в MS Word.</p>
<p>Сначала создадим шаблон, с которым и будем в дальнейшем работать.</p>
<p>Создайте новый документ MS Word. Лучше создавать не файл документа (расширение .Doc), а файл шаблона документа (расширение .Dot).</p>
<p>Теперь создайте в этом документе таблицу из 2 строк и любого количества столбцов. Это можно сделать, нажав иконку в виде таблицы. Если такой иконки нет, то выберите пункт меню "Таблица", подпункт "Нарисовать таблицу". Почему всего две строки? Сейчас объясню.</p>
<p>Первая строка будет строкой заголовка таблицы. Поставьте указатель курсора в любую ячейку первой строки таблицы, далее выберите пункт меню "Таблица", подпункт "Заголовки". Визуально ничего не изменилось. Однако если Вы снова выберете пункт меню "Таблица", то слева от подпункта "Заголовки" окажется "птичка". Т.е. текущая строка таблицы относится к заголовку таблицы.</p>
<p>Заголовок таблицы обладает тем свойством, что он автоматически копируется на новую страницу документа, если количество строк таблицы занимает больше, чем одну страницу. Собственно, можете сразу заполнить строку заголовка, т.к. вряд ли ее содержимое будет зависеть от данных в таблице FoxPro.</p>
<p>Итак, в результате, в документе появилась одна таблица из двух строк. Причем первая строка помечена как заголовок. Вторая строка предназначена для заполнения собственно данными.</p>
<p>Но ведь данных, скорее всего, будет больше, чем одна строка! Верно. Проблема только в том, что Вы заранее не знаете, сколько именно строк будет в таблице. Следовательно, придется формировать строки программно. В процессе заполнения таблицы.</p>
<p>Теперь, после всех этих предварительных подготовок, пишем собственно код в FoxPro.</p>
<div class="foxcode">
<pre class="bbcode">  
 *Создаем новый документ MS WORD на базе ранее созданного шаблона  
  LOCAL loWord as Word.Application   
  loWord = CREATEOBJECT('Word.Application')  
    
 * Делаем созданный экземпляр приложения Word видимым  
 * В реальном проекте эта команда дается в самом конце,  
 * но здесь выносим ее в начало для отладки  
  m.loWord.Visible = .T.  
    
 * Создаем новый документ MS WORD на базе ранее созданного шаблона  
  LOCAL loDoc as Word.Document  
  loDoc = m.loWord.Documents.Add(fullpath('TestWord.dot'))  
    
 * Формируем ссылку на таблицу документа Word  
 * В данном случае нужная таблица - это физически самая первая таблица   
 * в коллекции таблиц, расположенной непосредственно на листе документа  
  LOCAL loTable as Word.Table   
  loTable = m.loDoc.Tables(1)  
    
 * Для заполнения таблицы Word создадим таблицу в FoxPro  
  CREATE Cursor Test (TestId I, TestName C(10))  
  INSERT INTO Test (TestId, TestName) VALUES (1, "Первая")  
  INSERT INTO Test (TestId, TestName) VALUES (2, "Вторая")  
  INSERT INTO Test (TestId, TestName) VALUES (3, "Третья")  
  INSERT INTO Test (TestId, TestName) VALUES (4, "Четвертая")  
  INSERT INTO Test (TestId, TestName) VALUES (5, "Пятая")  
    
 * Теперь собственно заполнение  
 * Счетчик, показывающий, какую строку таблицы Word сейчас заполняем  
  LOCAL lnWordRowNum  
 * Первая строка таблицы Word - это заголовок, поэтому начальное значение равно 2  
  lnWordRowNum = 2  
  select Test  
  SCAN  
 	* Сначала сравниваю общее количество строк в таблице со значением счетчика  
  	IF m.loTable.Rows.Count &lt; m.lnWordRowNum  
 		* Если количество строк меньше, то создаю новую строку  
  		m.loTable.Rows.Add()  
  	ENDIF  
  	  
 	* И собственно заполнение  
  	m.loTable.Cell(m.lnWordRowNum,1).Range.Text = Test.TestId  
  	m.loTable.Cell(m.lnWordRowNum,2).Range.Text = Test.TestName  
  	  
 	* Увеличиваю значение счетчика заполняемой строки Word  
  	lnWordRowNum = m.lnWordRowNum + 1  
  ENDSCAN</pre>
</div>
<p>В этом коде 'TestWord.dot' - это имя созданного Вами файла шаблона. Здесь имя приведено просто в качестве примера. Использована функция FullPath(), чтобы получить полный путь доступа к этому файлу.</p>
<p>Синтаксис вида</p>
<div class="foxcode">
<pre class="bbcode">LOCAL loWord as Word.Application</pre>
</div>
<p>Это нововведение версии Visual FoxPro 7.0 для подключения механизма IntelliSens. Если у Вас младшая версия FoxPro, то можете писать в привычном синтаксисе.</p>
<div class="foxcode">
<pre class="bbcode">LOCAL loWord</pre>
</div>
<p>Собственно на работоспособность программы это никак не влияет. Это всего-лишь облегчение процесса программирования, но это никак, никоим образом, не влияет на работоспособность программы.</p>
<p>Существенным остается вопрос, откуда я узнал все эти методы и свойства собственно приложения MS Word. По большей части из документации по языку Microsoft Visual Basic, встроенному в программу MS Word. Встроен как сам язык, так и документация <img decoding="async" src="http://forum.foxclub.ru/mods/smileys/images/smile.gif" />.</p>
<p>Хотя, поиск существенно облегчил механизм IntelliSens в FoxPro. Я сразу вижу все свойства и методы того или иного объекта и предполагаю, что именно мне может понадобиться. Затем смотрю документацию по языку Microsoft Visual Basic и уточню, действительно ли это то, что мне надо.</p>
<p>Если количество строк в таблице MS Word всегда одно и то же, или же Вам надо заполнить определенные места в обычном текстовом документе, то для этого лучше воспользоваться рекомендациями, приведенными в другой статье:</p>
<p><a href="http://forum.foxclub.ru/read.php?32,177179,177221#msg-177221" target="_blank" rel="nofollow noopener noreferrer"><u>Как мне вывести данные в существующий MS WORD документ</u></a></p>
<p>Описанный в данной статье механизм заполнения таблицы относительно медленный, хотя и самый надежный. Впрочем, как правило, таблицы, заполняемые в MS Word относительно небольшого размера, поэтому общее время заполнения таблицы будет не велико. Если же процесс заполнения таблицы MS Word станет занимать слишком много времени, то следует подумать о способах оптимизации этого процесса. Есть разные варианты, но здесь их описывать не имеет смысла.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-zapolnit-tabliczu-v-ms-word/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с другими программами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-uznat-kakaya-komanda-word-ili-excel-vypolnyaet-nuzhnoe-dejstvie/</link>
					<title><![CDATA[Как узнать какая команда Word или Excel выполняет нужное действие]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:17:55 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как узнать какая команда Word или Excel выполняет нужное действие</h1>
													</header>
													<blockquote><p><b>Вопрос</b></p>
<p>Как узнать какая команда Word или Excel выполняет нужное действие.</p></blockquote>
<p><b>Ответ</b></p>
<p>В программах Word и Excel существует режим автоматической записи всех действий пользователя данных программ. Поэтому достаточно просто включить этот режим, выполнить необходимое действие и посмотреть какая же именно команда отвечает за его выполнение.</p>
<p>Для этого выбирается пункт меню Excel с именем "Сервис" - "Макрос" - "Начать запись". В появившемся окне указываем имя макроса (по умолчанию "Макрос1") и нажимаем кнопку "Ok". В результате, поверх листа Excel появляется маленькое специфическое окошко - ToolBar - с именем "Остановить запись" и все Ваши действия будут автоматически записываться.</p>
<p>После того, как Вы выполните все необходимые действия, остановите запись макроса. Для этого просто нажмите иконку с черным квадратиком в этом ToolBar с именем "Остановить запись". Далее выберите пункт меню Excel с именем "Сервис" - "Макрос" - "Макросы". Выберите имя только что записанного макроса (по умолчанию "Макрос1") и нажмите кнопку "Изменить".</p>
<p>Откроется окно редактора Micosoft Visual Basic в котором будет отображен код Вашего макроса.</p>
<p>Правда, следует заметить, что "в чистом виде" использовать полученный код макроса в FoxPro нельзя. Необходимо его слегка "адаптировать". Как это сделать рассматривается в статье</p>
<p><a href="http://www.foxclub.ru/articles/index.php?id=41" target="_blank" rel="nofollow noopener noreferrer"><u>Перевод макроса Excel в синтаксис FoxPro</u></a></p>
<p><em>Кроме того, следует понимать, что таким образом Вы сможете определить только те команды, которые можно визуализировать. Т.е. выполнение этих команд приводит к каким-либо изменениям на экране. Все прочие команды следует искать в справочном руководстве по диалекту языка Visual Basic соответствующего продукта</em>.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-uznat-kakaya-komanda-word-ili-excel-vypolnyaet-nuzhnoe-dejstvie/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с другими программами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-uznat-znachenie-konstanty-word-ili-excel/</link>
					<title><![CDATA[Как узнать значение константы Word или Excel]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:15:51 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как узнать значение константы Word или Excel</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Как узнать значение константы Word или Excel?</p>
<p><b>Ответ</b></p>
<ul>
<li>Откройте Word или Excel, для которых Вы хотите узнать значение константы</li>
<li>Выберите пункт главного меню "Сервис" - "Макрос" - "Редактор Visual Basic" (или по горячей клавише Alt+F11)</li>
<li>В открывшемся окне выберите пункт главного меню "View" - "Object Browser" (или по горячей клавише F2)</li>
<li>Далее в пустом окошке слева от кнопки с иконкой бинокля ввести имя искомой константы и нажать кнопку с иконкой бинокля (или клавишу Enter).
<p>В результате поиска в самом низу окна "Object Browser" будет отображено значение искомой константы.</li>
</ul>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-uznat-znachenie-konstanty-word-ili-excel/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с другими программами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-otkryt-fajl-v-drugom-prilozhenii/</link>
					<title><![CDATA[Как открыть файл в другом приложении]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:14:50 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как открыть файл в другом приложении</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>У меня есть файл, созданный в другом приложении (XLS, PDF, DOC и т.п.). Как мне из FoxPro открыть соответствующее приложение и открыть в нем этот файл.</p>
<p><b>Ответ</b></p>
<p>Для этой цели используется специальная API-функция <b>ShellExecute</b></p>
<div class="foxcode">
<pre class="bbcode">Declare Long ShellExecute in Shell32 ;   
  	Long 	hWnd, ;		&amp;&amp; хендл родительского окна  
  	String 	lpOperation, ;	&amp;&amp; что сделать с файлом "open", "print",  "explore"  
  	String 	lpFile, ;		&amp;&amp; имя файла. Можно с путем доступа  
  	String 	lpParameters, ;	&amp;&amp; используется только для исполняемых файлов  
  	String 	lpDirectory, ; 	&amp;&amp; директория, относительно которой надо искать файл  
  	Integer 	ShowCmd 	&amp;&amp; режим открытия приложения  
    
 * Это откроет Acrobat (если он есть)  
  mKod=ShellExecute(0, "open", "uidesign1.pdf", NULL, "C:\text", 1)   
    
 * Это отправит сразу на печать  
  mKod=ShellExecute(0, "print", "uidesign1.pdf", NULL, "C:\text", 1)   
    
 * Это откроет проводник Windows на указанной директории   
  mKod=ShellExecute(0, "explore", "C:\text", NULL, NULL, 1)</pre>
</div>
<p>Если функция ShellExecute вернула значение больше 32, то команда выполнена успешно. В противном случае произошла какая-то ошибка.</p>
<p>Следует иметь в виду, что функция ShellExecute откроет только те файлы, расширение которых ассоциировано в операционной системе Windows с каким-либо приложением. Например, если на машине пользователя не установлен Acrobat, то и файлы с расширением pdf не смогут быть открыты. Просто нечем.</p>
<p>Также следует понимать, что Вы не можете из FoxPro получить доступ к приложению открытому через ShellExecute. Это приложение будет открыто как отдельный независимый от FoxPro процесс.</p>
<p>Если у вас стоит задача только открыть файл, то можно воспользоваться COM-интерфейсом Shell API следующим образом</p>
<div class="foxcode">
<pre class="bbcode">  
  Local loShell  
  loShell = CreateObject('Shell.Application')  
  loShell.Open("C:\text\uidesign1.pdf")</pre>
</div>
<p>Кроме того, использование COM-интерфейса вызовет стандартный диалог Windows с предложением выбрать приложение, если в системе Windows не зарегистрировано приложение ассоциированное с указанным расширением файла.</p>
<p>К сожалению, через COM-интерфейс Shell API невозможно отправить документ на печать. В этом случае придется воспользоваться напрямую API-функцией ShellExecute</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-otkryt-fajl-v-drugom-prilozhenii/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с другими программами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-mne-vyvesti-dannye-v-sushhestvuyushhij-ms-word-dokument/</link>
					<title><![CDATA[Как мне вывести данные в существующий MS WORD документ]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sun, 30 Aug 2020 12:14:08 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как мне вывести данные в существующий MS WORD документ</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
Как мне вывести данные в существующий MS WORD документ?</p></blockquote>
<p><b>Ответ</b></p>
<p>Вариантов решения данной проблемы много. В данном случае будет рассмотрен вариант решения через предварительно созданный файл шаблона (файл с расширение DOT)</p>
<p>Сначала необходимо создать документ (шаблон) MS Word в который впоследствии будут вставлены нужные данные. Этот документ следует сохранить как шаблон MS Word.</p>
<p>В те места, где предполагается вставлять значения следует вставить специальные объекты, которые называются "Поля".</p>
<p>Эти объекты вставляются через пункт меню Word "Вставка", подпункт "Поле". При выборе данного пункта меню в появившейся форме следует выбрать поле с именем "<b>Quote</b>". Это поле относится к категории "Связи и ссылки". Введите в свойстве поля "Текст" какой-либо текст (он будет заменен при заполнении из FoxPro), установите, если надо, формат данных и нажмите кнопку "Ok".</p>
<p>Поле будет вставлено в документ MS Word, однако по умолчанию этот факт никак не отображается. Чтобы наглядно увидеть вставленный объект выделите весь текст, нажмите на выделенном тексте правой клавишей мыши и выберите пункт открывшегося меню "Коды/Значения полей".</p>
<p>То же самое можно сделать через общие настройки MS Word. Пункт главного меню "Сервис" - подпункт "Параметры" - Закладка "Вид" - Раздел "Показывать" - птичка "Коды полей".</p>
<p>Чтобы внести изменения в код поля выделите его, нажмите правую кнопку мыши и выберите пункт открывшегося меню "Изменить поле".</p>
<p>Повторите вставку "Поля" во все места, где Вы предполагаете впоследствии подставить собственные данные.</p>
<p>Если Вы хотите сделать вставку в таблицы в MS Word, то в ячейках этих таблиц вообще ничего не надо вставлять.</p>
<p>Все. С предварительной подготовкой закончили. Сохраните полученный документ как шаблон MS Word и закройте его.</p>
<p>Программное наполнение такого предварительно созданного шаблона будет выглядеть примерно так:</p>
<div class="foxcode">
<pre class="bbcode">  
 * Создаем новый документ MS WORD на базе ранее созданного шаблона  
  LOCAL loWord, loDoc  
  loWord = CREATEOBJECT( 'WORD.APPLICATION')    
  loDoc=m.loWord.Documents.Add('Полный_путь_доступа'+'Имя_файла_шаблона.dot')  
    
 * Подставляем необходимые значения в поля   
  m.loDoc.Fields(число_порядковый_номер_поля).Result.text="Текст"  
    
 * Для заполнения данных таблиц WORD принцип такой  
  m.loDoc.Tables(число_порядковый_номер_таблицы).Cell(число_ряд,число_колонка).Range.Text="Текст"  
    
 * Делаем созданный документ видимым  
  m.loWord.Visible = .T.</pre>
</div>
<p>Однако рассмотренный вариант имеет тот недостаток, что к созданным полям приходится обращаться по номерам. Это не всегда удобно. Было бы проще, если бы поля имели символьное обозначение. Поэтому, рассмотрим еще один вариант.</p>
<p>Также предварительно создаем файл шаблона, но в качестве вставляемых объектов будем использовать не "Поля", а "Поля формы". Для этого надо активизировать специальный ToolBar с именем "Формы" (Пункт главного меню "Вид" - "Панели инструментов" - "Формы").</p>
<p>Вставляем курсор на нужное место в шаблоне и нажимаем на панели инструментов "Формы" самую левую иконку с буквами "ab". В текущее место шаблона будет вставлен специальный объект "Поле формы".</p>
<p>Дважды щелкните левой клавишей мыши по "Полю формы" и откроется дополнительное окно свойств этого объекта. Сейчас нас интересует его свойство "Закладка". Это и будет то самое, символьное обозначение объекта, по которому к нему можно будет обратиться из программы.</p>
<p>Это обозначение (закладка) может быть любое. Единственное ограничение - оно должно быть уникально в пределах всего шаблона. Впрочем, за этим проследит сам Word.</p>
<p>Предположим, что Вы оставили закладку в значении по умолчанию "ТекстовоеПоле1". Тогда изменение его содержимого из программы будет иметь вид:</p>
<div class="foxcode">
<pre class="bbcode">  
 * Создаем новый документ MS WORD на базе ранее созданного шаблона  
  LOCAL loWord, loDoc  
  loWord = CREATEOBJECT( 'WORD.APPLICATION')    
  loDoc=m.loWord.Documents.Add('Полный_путь_доступа'+'Имя_файла_шаблона.dot')  
    
 * Подставляем необходимые значения в поля   
  IF TYPE([m.loDoc.FormFields("ТекстовоеПоле1")])="O"  
  	m.loDoc.FormFields("ТекстовоеПоле1").Result="Новое значение"  
  ENDIF  
    
 * Делаем созданный документ видимым  
  m.loWord.Visible = .T.</pre>
</div>
<p>К сожалению, такой синтаксис возможен только для Word 2000 или старше. Для младших версий Word придется по старинке обращаться через порядковый номер. Точнее, надо будет сканировать коллекцию FormFields на предмет поиска "Поля формы" со свойством Name = "ТекстовоеПоле1". Примерно так:</p>
<div class="foxcode">
<pre class="bbcode">  
  LOCAL lnI  
  FOR lnI=1 TO m.loDoc.FormFields.Count  
  	IF m.loDoc.FormFields(m.lnI).Name == "ТекстовоеПоле1"  
  		m.loDoc.FormFields(m.lnI).Result="Новое значение"  
  	ENDIF  
  ENDFOR</pre>
</div>
<p>&nbsp;</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-mne-vyvesti-dannye-v-sushhestvuyushhij-ms-word-dokument/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с другими программами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-poluchit-razniczu-dvuh-dat-v-formate-let-mesyaczev-dnej/</link>
					<title><![CDATA[Как получить разницу двух дат в формате: лет, месяцев, дней]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:59:28 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как получить разницу двух дат в формате: лет, месяцев, дней</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
Как получить разницу двух дат в формате: лет, месяцев, дней</p></blockquote>
<p><b>Ответ</b></p>
<p><u>В общем случае</u>, данный вопрос не имеет решения.</p>
<p>Пожалуйста, не надо сразу бросаться писать опровержения, что вот у меня есть готовый код, который это делает или вот есть ссылка на решение. Сначала дочитайте до конца, что именно подразумевается в данном случае под фразой "решения не имеет".</p>
<p>Проблема заключается в том, что нет однозначного определения того, что есть "месяц" и "год". Как правило, под этим подразумевают календарные месяцы. Но сложность в том, что календарный месяц - это понятие не абсолютное, а относительное. Календарный месяц - это не просто некоторое количество дней. Это количество дней, прошедших с определенной даты.</p>
<p>Для лучшего понимания проблемы рассмотрим простой пример.</p>
<p><i>Надо определить разницу дат между 30 января и 2 апреля одного 2008 года.</i></p>
<p>Если бы задача заключалась в определении количества дней, то все решалось бы простым вычитанием</p>
<pre class="bbcode">?{^2008-04-02} - {^2008-01-30} &amp;&amp; 63 дня</pre>
<p>А как определить количество месяцев? Результат будет существенно зависеть от того, как именно будет определяться один месяц. Возможно несколько идеологий расчета:</p>
<p><b>Вариант 1</b></p>
<p>Прибавляем к начальной дате последовательно по одному месяцу до тех пор, пока результат не превысит конечной даты.</p>
<p>Под термином "месяц" в процессе прибавления подразумевается такая операция, в результате которой номер дня остается тот же самый, а номер месяца увеличивается на 1. Если у нового месяца нет такой даты, то устанавливается дата равная последнему дню нового месяца. Так работает функция GoMonth()</p>
<p>Это значит, что если прибавить один месяц к 30 января, то получим 29 февраля (2008 год - високосный), поскольку в феврале нет 30 числа.</p>
<p>Затем прибавляем к 29 февраля еще один месяц, получаем 29 марта. Прибавлять еще один месяц уже не надо, поскольку результат будет заведомо больше 2 апреля.</p>
<p>Между 29 марта и 2 апреля остается 4 дня. Значит, результат будет <b>2 месяца и 4 дня</b>.</p>
<p>Заметьте, что в не високосном году результат был бы <b>2 месяца и 5 дней</b></p>
<p>Обратите внимание на тот факт, что если начальная дата равна 29, 30 или 31 января результат был бы один и тот же! Поскольку прибавление одного месяца давало бы все то же 29 февраля. Получается парадоксальная ситуация - количество дней разное, а результат одинаковый.</p>
<p><b>Вариант 2</b></p>
<p>Алгоритм похож на "Вариант 1", но прибавлять будем не по одному месяцу за раз, а сразу прибавим столько месяцев, чтобы оказаться как можно ближе к конечной дате. Т.е. прибавим к 30 января сразу 2 месяца и получим 30 марта.</p>
<p>Между 30 марта и 2 апреля остается 3 дня. Значит, результат будет <b>2 месяца и 3 дня</b>.</p>
<p>Заметьте, что если бы конечным месяцем был бы не апрель, а март, то данный вариант расчета ничем не отличался бы от "Варианта 1".</p>
<p><b>Вариант 3</b></p>
<p>Под термином "месяц" будем понимать именно календарный месяц. Т.е. февраль - это интервал от 01 февраля до 29 февраля, март - это интервал от 01 марта до 31 марта.</p>
<p>В этом случае имеем 2 полных месяца - февраль и март. И "остатки" от граничных месяцев: 1 день до конца января и 2 дня апреля. Значит, результат будет <b>2 месяца и 3 дня</b>.</p>
<p>Но в данном случае повезло. Оставшихся дней явно не хватает для полного месяца. А если бы оставшихся дней было бы, например, 40 (с 10 января по 20 апреля)? Встал бы вопрос, сколько дней надо выделить из этого количества дней, чтобы получить еще 1 месяц? Берем количество дней в январе (месяце начала периода) или в апреле (месяце конца периода)?</p>
<p><b>Вариант 4</b></p>
<p>Принимаем, что все месяцы имеют одинаковое количество дней, которое вычисляется по следующей формуле:</p>
<pre class="bbcode">(365+365+365+366)/4/12 = 30.4375</pre>
<p>Тогда количество месяцев - это просто отношение количества дней к данной константе, округленное до целого. Значит, результат будет <b>2 месяца и 2 дня</b>.</p>
<p><i>Могут быть и другие варианты расчета</i>.</p>
<p>Как видите, результат <b>существенно</b> зависит от того, что именно понимается под термином "месяц". Точнее, как именно этот самый месяц выделяется в заданном диапазоне. Причем, даже нельзя сказать, что один способ является "правильным", а другие "не правильные". Они все "правильные". Но в рамках определенной идеологии.</p>
<p>Другими словами, вопрос расчета интервала в формате "лет, месяцев, дней" заключается не столько в коде, сколько в идеологии (алгоритме) расчета. Как только будет принята определенная идеология расчета, запрограммировать ее не составит труда.</p>
<p>Выбор того или иного способа определения месяца, как правило, определяется той задачей, которую необходимо решить. Просто поздравить именинника (можно и несколько дней подряд - не страшно <img decoding="async" src="http://forum.foxclub.ru/mods/smileys/images/smile.gif" /> ), определить трудовой стаж или статистика в родильном отделении.</p>
<p>Следует еще заметить, что те же проблемы касаются и определения любых других календарных интервалов. Таких как "неделя", "квартал", "год". Т.е. прежде чем писать код, необходимо описать по каким правилам будут определяться указанные интервалы.</p>
<p>Вы можете поискать уже готовые примеры расчета на данном сайте или в интернете. Но всегда следует иметь в виду, что все эти примеры кодируют определенную идеологию определения месяца и года. К сожалению, как именно (по какой идеологии) происходит это определение из кода далеко не всегда видно. Поэтому, результат работы найденных примеров может оказаться далек от ожидаемых Вами. Каждый пример следует тщательно протестировать для определения его пригодности под Вашу конкретную задачу.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-poluchit-razniczu-dvuh-dat-v-formate-let-mesyaczev-dnej/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Program]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-vyvesti-prilozhenie-na-perednij-plan/</link>
					<title><![CDATA[Как вывести приложение на передний план]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:56:28 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как вывести приложение на передний план</h1>
													</header>
													<blockquote><p><b>Вопрос</b></p>
<p>Как вывести на передний план и активизировать окно нужного приложения. Это может быть окно Word, или ранее запущенное приложение FoxPro, или форма для ввода логина и пароля в приложении FoxPro (иногда она не выводится на передний план)</p></blockquote>
<p><b>Ответ</b></p>
<p>Идея решения принадлежит Вадиму Пирожкову (piva)</p>
<p>Для вывода окна <u>любого</u> приложения на передний план, необходимо знать текст заголовка нужного окна.</p>
<pre class="bbcode">  
  LOCAL loShell, lcCaption  
  loShell=CreateObject("WScript.Shell")      
  lcCaption = "Заголовок_нужного_Окна"  
  IF loShell.AppActivate(m.lcCaption) = .T.  
  	loShell.SendKeys("% ~")  
  ELSE  
  	MessageBox("Приложение "+m.lcCaption+" не найдено")  
  ENDIF</pre>
<p>Метод loShell.AppActivate() выполняет поиск приложения по первым символам заголовка нужного окна и активизирует его, что сопровождается выводом окна на передний план. Если указанного окна обнаружить не удалось, то данный метод вернет .F., но никакого сообщения об ошибке не будет.</p>
<p>Проблема в том, что метод loShell.AppActivate() выводит приложение на передний план "как есть". Например, если приложение было свернуто (минимизировано), то оно, конечно, будет активизировано. Но активизировано в том же, свернутом, состоянии.</p>
<p>Чтобы приложение развернуть на весь экран необходимо выполнить некоторые манипуляции в самом приложении. Нажать некую последовательность клавиш. Вот именно этим и занимается метод loShell.SendKeys() - посылает в активное приложение некоторый набор кодов клавиш.</p>
<p>В данном случае набор посылаемых клавиш основан на том факте, что большинство приложений имеет системное меню, которое вызывается комбинацией клавиш "ALT+пробел". Это системное меню раскрывается также по нажатию клавиши мыши в левом верхнем углу приложения на иконке самого приложения.</p>
<p>Данное меню содержит пункты по управлению размером и положением окна. Причем самый первый пункт этого меню "Восстановить". Этот пункт (поскольку он первый) автоматически становится активным при открытии меню. Остается только нажать клавишу Enter для его выбора.</p>
<p>Вот именно эта последовательность клавиш - ALT+пробел+ENTER - и зашифрована в параметре метода</p>
<pre class="bbcode">loShell.SendKeys("% ~")</pre>
<p>Если Вы уверены, что активизируемое Вами приложение находится в "нормальном", развернутом состоянии, то вызывать метод loShell.SendKeys() нет необходимости.</p>
<p>Также вызывать именно эту последовательность нажатия клавиш не имеет смысла, если приложение не имеет стандартного системного меню. В FoxPro подавить активизацию системного меню можно, например, установив свойство</p>
<pre class="bbcode">_SCREEN.ControlBox = .F.</pre>
<p>Условное обозначение кодов клавиш, используемых в методе SendKeys(), приведено в следующей таблице</p>
<pre class="bbcode">  
  <b>Key 		Code</b>   
  BACKSPACE 	{BACKSPACE}, {BS}, or {BKSP}   
  BREAK 		{BREAK}   
  CAPS LOCK 	{CAPSLOCK}   
  DEL or DELETE 	{DELETE} or {DEL}   
  DOWN ARROW 	{DOWN}   
  END 		{END}   
  ENTER 		{ENTER}or ~   
  ESC 		{ESC}   
  HELP 		{HELP}   
  HOME 		{HOME}   
  INS or INSERT 	{INSERT} or {INS}   
  LEFT ARROW 	{LEFT}   
  NUM LOCK 	{NUMLOCK}   
  PAGE DOWN 	{PGDN}   
  PAGE UP 	{PGUP}   
  PRINT SCREEN 	{PRTSC}   
  RIGHT ARROW 	{RIGHT}   
  SCROLL LOCK 	{SCROLLLOCK}   
  TAB 		{TAB}   
  UP ARROW 	{UP}   
  F1 		{F1}   
  F2 		{F2}   
  F3 		{F3}   
  F4 		{F4}   
  F5 		{F5}   
  F6 		{F6}   
  F7 		{F7}   
  F8 		{F8}   
  F9 		{F9}   
  F10 		{F10}   
  F11 		{F11}   
  F12 		{F12}   
    
  <b>Key 		Code </b>  
  SHIFT 		+   
  CTRL 		^   
  ALT 		%</pre>
<p>Все прочие клавиши в методе SendKeys() выводятся как буквы соответствующих клавишь или их ASCII-коды в функции Chr(). Например, вместо символа "~" можно указать код chr(13) или {ENTER}</p>
<pre class="bbcode">  
  loShell.SendKeys("% "+chr(13))  
 * или  
  loShell.SendKeys("% {ENTER}")</pre>
<p><u><i>Как вывести на передний план текущее приложение FoxPro</i></u></p>
<p>В этом случае, заголовком приложения является значение свойства</p>
<p>_SCREEN.Caption</p>
<pre class="bbcode">  
  LOCAL loShell  
  loShell=CreateObject("WScript.Shell")      
  loShell.AppActivate(_SCREEN.Caption)</pre>
<p>В данном случае, как раз нет смысла использовать метод SendKeys() в силу того, что нужное Вам окно заведомо находится в нужном состоянии.</p>
<p><u><i>Как вывести на передний форму со свойством Form.ShowWindow = 2 - As Top-Level</i></u></p>
<p>Как правило, такие формы используются для ввода логина и пароля пользователя при открытии приложения. Однако, по умолчанию, на передний план выводится окно собственно среды FoxPro (_SCREEN), если до вызова формы была предпринята попытка активизировать основное окно FoxPro или сделать в него вывод какой-либо информации. Поэтому, зачастую, форма для ввода логина и пароля открывается, но на передний план не выводится.</p>
<p>В этом случае, в качестве заголовка окна используется заголовок формы.</p>
<pre class="bbcode">  
 * Вызываю форму для ввода логина и пароля  
  DO FORM MyTopForm.scx    
    
 * Вывожу ее на передний план  
  LOCAL loShell  
  loShell=CreateObject("WScript.Shell")      
  loShell.AppActivate(MyTopForm.Caption)  
    
 * Организую точку останова приложения  
  READ EVENTS</pre>
<p>В данном случае, как раз нет смысла использовать метод SendKeys() в силу того, что нужное Вам окно заведомо находится в нужном состоянии.</p>
<p><u><i>Как вывести на передний план приложение Word или Excel в котором сформировали отчет</i></u></p>
<p>Довольно распространенный способ формирования отчетов - это прямое заполнение документов в Word или Excel. Естественно, после формирования отчета хотелось бы вывести его на передний план.</p>
<p><b>Приложение Word</b></p>
<pre class="bbcode">  
 * Создание экземпляра приложения Word  
  LOCAL loWord as Word.Application  
  loWord = CreateObject("Word.Application")  
 * Далее идет создание заполнение документа   
  ...  
 * Сформированный документ делается видимым  
  loWord.Visible = .T.  
    
 * Выводится экземпляр приложения Word на передний план  
  LOCAL loShell  
  loShell=CreateObject("WScript.Shell")      
  IF loShell.AppActivate(loWord.Caption) = .T.    
  	loShell.SendKeys("% ~")    
  ELSE    
  	MessageBox("Приложение "+loWord.Caption+" не найдено")    
  ENDIF</pre>
<p><b>Приложение Excel</b></p>
<pre class="bbcode">  
 * Создание экземпляра приложения Excel  
  LOCAL loExcel as Excel.Application  
  loExcel = CreateObject("Excel.Application")  
 * Далее идет создание и заполнение документа  
  ...  
 * Сформированный документ делается видимым  
  loExcel.Visible = .T.  
    
 * Выводится экземпляр приложения Excel на передний план  
  LOCAL loShell  
  loShell=CreateObject("WScript.Shell")      
  IF loShell.AppActivate(loExcel.Caption) = .T.    
  	loShell.SendKeys("% ~")    
  ELSE    
  	MessageBox("Приложение "+loExcel.Caption+" не найдено")    
  ENDIF</pre>
<p>Однако в отношении Word или Excel есть специфический способ активизации, основанный на том, что разворачивание этого окна на максимум из свернутого (минимизированного) состояния автоматически приводит к его активизации.</p>
<p><b>Приложение Word</b></p>
<pre class="bbcode">  
 * Выводится экземпляр приложения Word на передний план  
  #DEFINE wdWindowStateMinimize 2  
  #DEFINE wdWindowStateMaximize 1  
    
  loWord.WindowState = wdWindowStateMinimize	&amp;&amp; Сворачиваем окно  
  loWord.WindowState = wdWindowStateMaximize	&amp;&amp; Разворачиваем окно, что приводит к его активизации  </pre>
<p><b>Приложение Excel</b></p>
<pre class="bbcode">  
 * Выводится экземпляр приложения Excel на передний план  
  #DEFINE xlMinimized -4140  
  #DEFINE xlMaximized -4137  
    
  loExcel.WindowState = xlMinimized	&amp;&amp; Сворачиваем окно  
  loExcel.WindowState = xlMaximized	&amp;&amp; Разворачиваем окно, что приводит к его активизации  </pre>
<p>В качестве констант для сворачивания и разворачивания Excel можно также использовать значения 1 и 2 из набора констант Word.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-vyvesti-prilozhenie-na-perednij-plan/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Program]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-rabotat-s-putyami-dostupa-i-imenami-fajlov-soderzhashhih-probely/</link>
					<title><![CDATA[Как работать с путями доступа и именами файлов, содержащих пробелы]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:54:09 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как работать с путями доступа и именами файлов, содержащих пробелы</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
При использовании путей доступа или имен файлов, содержащих пробелы, я получаю сообщения об ошибках. Как работать с путями доступа и именами файлов, содержащих пробелы?</p></blockquote>
<p><b>Ответ</b></p>
<p>В общем случае следует обрамлять такие имена кавычками или использовать выражения имени.</p>
<p>Например, на Вашем компьютере есть файл по такому пути доступа:</p>
<blockquote class="bbcode"><p>Цитата:</p>
<div>C:\Мои документы\Мой файл.txt</div>
</blockquote>
<p>Если Вы хотите обратиться к такому файлу напрямую, по имени, то это следует делать так:</p>
<pre class="bbcode">MODIFY FILE "C:\Мои документы\Мой файл.txt"</pre>
<p>Если Вы считали это имя в переменную памяти, например, при помощи функции GetFile() или имя директории при помощи функции GetDir(), то следует использовать выражение имени. Скобки.</p>
<pre class="bbcode">  
  LOCAL lcFileName  
  lcFileName = GetFile()  
  MODIFY FILE (m.lcFileName)</pre>
<p>В принципе, можно использовать и символ макроподстановки. Но в этом случае нужно достаточно хорошо понимать, что именно происходит в этом случае. Дело в том, что при использовании символа макроподстановки происходит формальная замена переменной памяти на тот текст, который в ней записан. Другими словами код</p>
<pre class="bbcode">  
  LOCAL lcFileName  
  lcFileName = "C:\Мои документы\Мой файл.txt"  
  MODIFY FILE &amp;lcFileName</pre>
<p>фактически преобразуется в такой код</p>
<pre class="bbcode">MODIFY FILE C:\Мои документы\Мой файл.txt</pre>
<p>Далее вступает в действие синтаксический анализатор кода. Для него имя файла - это параметр команды. А параметры, в данном случае, отделяются друг от друга пробелами. Следовательно, FoxPro прочитает данную команду следующим образом:</p>
<pre class="bbcode">MODIFY FILE C:\Мои</pre>
<p>Разумеется, ни такой директории, ни имени файла не существует. И Вы получаете сообщение об ошибке.</p>
<p>Чтобы предотвратить подобное развитие событий, необходимо добавить дополнительные кавычки</p>
<pre class="bbcode">  
  LOCAL lcFileName  
  lcFileName = ["C:\Мои документы\Мой файл.txt"]  
  MODIFY FILE &amp;lcFileName</pre>
<p>Этот код будет прочитан следующим образом</p>
<pre class="bbcode">MODIFY FILE "C:\Мои документы\Мой файл.txt"</pre>
<p>Вот здесь уже все в полном порядке. Параметр - это то, что ограничено кавычками.</p>
<p>Хотя, разумеется, использование дополнительных кавычек не слишком удобно. Поэтому проще при работе с именами файлов использовать выражения имени. Т.е. скобки. В этом случае Вы автоматически страхуетесь от возможных пробелов в именах файлов и путях доступа.</p>
<pre class="bbcode">  
  LOCAL lcFileName  
  lcFileName = "C:\Мои документы\Мой файл.txt"  
  MODIFY FILE (m.lcFileName)</pre>
<p>&nbsp;</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-rabotat-s-putyami-dostupa-i-imenami-fajlov-soderzhashhih-probely/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Program]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/simvolnye-polya-peremennye-pamyati-i-konstanty/</link>
					<title><![CDATA[Символьные поля, переменные памяти и константы]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:52:57 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Символьные поля, переменные памяти и константы</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Я формирую запрос через SQLExec() или макроподстановку. Почему не получается сформировать запрос более чем на 255 символов?</p>
<p><b>Ответ</b></p>
<p><b>Символьные поля, переменные памяти и константы</b></p>
<p>В FoxPro существует отличия в предельно допустимой длине символьных данных в зависимости от того, о чем идет речь: поле таблицы, переменной памяти или константе</p>
<p>Ну, с полями таблицы все ясно. Их предельная длина определяется собственно размерностью поля. Однако размерность поля не может превышать 254 символов. Для memo-полей объем не может превышать 2ГБ (2 гигабайта - это 2 и 9 нулей символов).</p>
<p>Длина символьной константы не может превышать 255 символов</p>
<p>Длина символьной переменной теоретически не может превышать 16,777,184 символов. "Теоретически", потому, что при определенных условиях все-таки может. Просто за последствия такого превышения никто не отвечает.</p>
<p>Отдельно следует остановиться на отличии символьной константы от символьной переменной. Начинающие программисты очень часто получают сообщение об ошибке "Command contains unrecognized phrase/keyword (Error 36)" именно в силу непонимания этой разницы.</p>
<p>В FoxPro для написания символьных констант можно использовать 3 символа: одинарные кавычки, двойные кавычки, квадратные скобки. В чем отличие символьной константы от символьной переменной проще объяснить на примере. Словами получится долго и невнятно. Например:</p>
<pre class="bbcode">  
  LOCAL lcString  
  lcString = 'Начало строки' + " середина строки " + [окончание строки]</pre>
<p>Так вот, здесь то, что записано в кавычках и квадратных скобках - это 3 символьные константы, а lcString - это одна символьная переменная</p>
<p>Вообще-то, лично мне трудно представить, как можно написать одну символьную константу длиной больше 255 символов. Точнее написать-то такое можно, но как потом это можно редактировать! Получится совершенно не "читабельный" текст. Я рекомендовал бы разбивать длинные символьные константы на небольшие фрагменты с тем, чтобы каждый отдельный фрагмент целиком помещался в окне редактирования. Примерно так:</p>
<pre class="bbcode">  
  LOCAL lcString  
  lcString = "Начало строки"+;  
        " середина строки "+;  
        "окончание строки"</pre>
<p>В FoxPro нет специальных управляющих символов, как, например, в C используется обратный слеш. Поэтому, если Вам надо использовать кавычки не как границу символьной константы, а как собственно символ, то просто обрамляйте их кавычками другого типа:</p>
<pre class="bbcode">?[ЗАО "Рога и копыта"]</pre>
<p>Следует всегда помнить, что FoхPro отличается определенной "самостоятельностью" в преобразовании данных. Применительно к символьным данным это проявляется в том, что если Вы попытаетесь записать в символьное поле больше символов, чем позволяет его размерность, то ошибки это не вызовет, просто "лишние" символы будут отброшены без каких-либо дополнительных сообщений об ошибках.</p>
<pre class="bbcode">  
  CREATE CURSOR test (test C(5))  
  INSERT INTO test (test) VALUES ("1234567890")  
  ?test.test</pre>
<p>Если Вам надо записать в переменную памяти несколько строк текста "как есть", то, начиная с версии Visual FoxPro 7 для этой цели лучше использовать скобки TEXT...ENDTEXT</p>
<pre class="bbcode">  
  LOCAL lcText  
    
  TEXT TO m.lcText NOSHOW  
  Первая строка текста  
  Вторая строка текста  
  "Название"  
  ENDTEXT  
    
  ?m.lcText</pre>
<p>Как видите, все что находится между TEXT и ENDTEXT воспринимается не как набор команд, а просто как текст. Содержимое переменой m.lcText.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/simvolnye-polya-peremennye-pamyati-i-konstanty/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Program]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-rabotat-s-ini-fajlami/</link>
					<title><![CDATA[Как работать с ini-файлами]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:51:58 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как работать с ini-файлами</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
Как работать (читать и записывать) с ini-файлами?</p></blockquote>
<p><b>Ответ</b></p>
<p><em>ini-файл или файл с расширением из 3 букв "INI" (от слов initialization file - файл инициализации) - это обычный текстовый файл, который имеет специфическое содержание.</em> Выглядит его содержимое примерно так:</p>
<pre>// Комментарий
[Имя_раздела_1]
Имя_реквизита_1 = значение реквизита
Имя_реквизита_2 = значение реквизита

// Комментарий
[Имя_раздела_2]
Имя_реквизита_1 = значение реквизита
Имя_реквизита_2 = значение реквизита</pre>
<p>Т.е. в квадратных скобках указывается имя раздела (другое название - "секция"), затем идет список реквизитов (другое название - "ключ") этого раздела и их значение. Количество разделов и количество реквизитов внутри раздела не ограничено.</p>
<p>Желательно давать имена разделам и реквизитам в одно слово из латинских букв без пробелов и спец.символов. Но это скорее перестраховка. Если для Вас удобнее воспринимать имя раздела или реквизита с пробелом (в два слова) - пишите с пробелом!</p>
<p>В качестве значения реквизита принимается вся строка от первого отличного от пробела символа после символа равенства до окончания строки, включая пробелы. Т.е. здесь для задания текстовой строки использовать кавычки не надо. Предполагается, что все значения имеют только и исключительно символьный тип.</p>
<p>Символом комментария обычно служит две наклонные черты подряд. Хотя, в принципе, можно использовать абсолютно любой символ (вот только пробел нельзя <img decoding="async" src="http://forum.foxclub.ru/mods/smileys/images/smile.gif" /> ). Для используемых ниже API-функций важен факт совпадения искомого имени начиная с первого символа. Достаточно того, чтобы первый символ не совпадал с искомым.</p>
<p>В принципе, можно прочитать такой файл из FoxPro функциями чтения текстовых файлов (FOPEN(), FREAD(), FileToStr() и т.п.) и сделать его разбор. "Но есть способ лучше" (с). Существуют специальные API-функции предназначенные для чтения и записи INI-файлов.</p>
<p><b>GetPrivateProfileString</b> - считывает значение указанного реквизита из указанного раздела.<br />
<b>WritePrivateProfileString</b> - записывает значение указанного реквизита в указанный раздел указанного ini-файла. Если указанного раздела или реквизита не существует, то он будет создан. Если указанного ini-файла не существует, то он также будет создан.</p>
<p>Выглядит это примерно так:</p>
<p><u><b>Запись значения в ini-файл</b></u></p>
<pre class="bbcode">  
  Declare Integer WritePrivateProfileString In Win32API As WritePrivStr ;    
  	String cSection, ;	&amp;&amp; имя раздела  
  	String cKey, ;	&amp;&amp; имя реквизита  
  	String cValue, ;	&amp;&amp; значение реквизита  
  	String posfile	&amp;&amp; имя ini-файла <u>с полным путем доступа</u>  
    
  LOCAL lnError  
  lnError = WritePrivStr("TestSection", ;  
  			"TestKey", ;  
  			"TestValue", ;  
  			Fullpath("test.ini"))  
  IF lnError&lt;&gt;1  
 	* Запись в ini-файл не удалась. Произошла ошибка  
  ELSE  
 	* Смотрим, что получилось во вновь созданном файле  
  	MODIFY FILE test.ini  
  ENDIF</pre>
<p><u><b>Чтение значения из ini-файл</b></u></p>
<pre class="bbcode">  
  Declare Integer GetPrivateProfileString In Win32API  As GetPrivStr ;    
  	String cSection, ;		&amp;&amp; Имя раздела  
  	String cKey, ;		&amp;&amp; Имя реквизита  
  	String cDefault, ;		&amp;&amp; Значение по умолчанию, если нет указанного раздела или реквизита  
  	String @cBuffer, ;		&amp;&amp; Собственно считанное значение реквизита  
  	Integer nBufferSize, ;	&amp;&amp; Максимальное количество символов в считанном реквизите  
  	String posfile		&amp;&amp; имя ini-файла <u>с полным путем доступа</u>  
    
  LOCAL lcBuffer, lnBuffer  
  lcBuffer = SPACE(2000)  
    
  lnBuffer = GetPrivStr("TestSection", ;  
  			"TestKey", ;  
  			"Нет значения", ;  
  			@lcBuffer, ;  
  			LEN(m.lcBuffer), ;  
  			Fullpath("test.ini"))  
    
  IF m.lnBuffer = 0  
 	* Ничего не прочитали  
  ELSE  
 	* Прочитанное значение храниться в первых m.lnBuffer символах переменной m.lcBuffer  
  	?LEFT(m.lcBuffer,m.lnBuffer)  
 	* Общая длина переменной m.lcBuffer по прежнему 2000 символов,   
 	* но символ m.lnBuffer+1 имеет ASCII-код равный 0, а все прочие - пробелы  
  ENDIF</pre>
<p><b><u>Удаление раздела или реквизита</u></b><br />
Удаление - это <b>запись</b> не определенного значения</p>
<pre class="bbcode">  
 * Удаление только одного реквизита TestKey в разделе TestSection  
  LOCAL lnError  
  lnError = WritePrivStr("TestSection", ;  
  			"TestKey", ;  
  			NULL, ;  
  			Fullpath("test.ini"))  
  IF lnError&lt;&gt;1  
 	* Запись в ini-файл не удалась. Произошла ошибка  
  ELSE  
 	* Смотрим, что получилось   
  	MODIFY FILE test.ini  
  ENDIF  
    
 * Удаление всего раздела TestSection со всеми реквизитами  
  LOCAL lnError  
  lnError = WritePrivStr("TestSection", ;  
  			NULL, ;  
  			NULL, ;  
  			Fullpath("test.ini"))  
  IF lnError&lt;&gt;1  
 	* Запись в ini-файл не удалась. Произошла ошибка  
  ELSE  
 	* Смотрим, что получилось   
  	MODIFY FILE test.ini  
  ENDIF</pre>
<p><b><u>Определение структуры ini-файла</u></b></p>
<p>Если структура ini-файла, т.е. имена секций и ключей, заранее не известны, то получить структуру ini-файла можно также используя функцию <b>GetPrivateProfileString</b> указав вместо имени секции или ключа число 0.</p>
<p>В этом случае в качестве возвращаемого значения Вы получите либо список имен секций (если указать 0 первым параметром), либо список имен ключей указанной секции (если указать 0 вторым параметром). Имена будут разделены символом Chr(0)</p>
<pre class="bbcode">  
 * Список секций ini-файла  
  LOCAL lcBuffer, lnBuffer  
  lcBuffer = SPACE(2000)  
    
  lnBuffer = GetPrivStr(0, ;  
  			0, ;  
  			"", ;  
  			@lcBuffer, ;  
  			LEN(m.lcBuffer), ;  
  			Fullpath("test.ini"))  
    
  IF m.lnBuffer &gt; 0  
  	m.lcBuffer = CHR(0) + LEFT(m.lcBuffer,m.lnBuffer)  
  	LOCAL lnI, lnFromPos, lnToPos  
  	FOR m.lnI = 1 TO OCCURS(CHR(0),m.lcBuffer)-1  
  		lnFromPos = AT(CHR(0),m.lcBuffer,m.lnI)  
  		lnToPos = AT(CHR(0),m.lcBuffer,m.lnI+1)  
  		?SubStr(m.lcBuffer,m.lnFromPos+1,m.lnToPos-m.lnFromPos-1)  
  	ENDFOR  
  ENDIF  
    
 * Аналогично получаем список ключей секции TestSection   
  LOCAL lcBuffer, lnBuffer  
  lcBuffer = SPACE(2000)  
    
  lnBuffer = GetPrivStr("TestSection", ;  
  			0, ;  
  			"", ;  
  			@lcBuffer, ;  
  			LEN(m.lcBuffer), ;  
  			Fullpath("test.ini"))  
    
  IF m.lnBuffer &gt; 0  
  	m.lcBuffer = CHR(0) + LEFT(m.lcBuffer,m.lnBuffer)  
  	LOCAL lnI, lnFromPos, lnToPos  
  	FOR m.lnI = 1 TO OCCURS(CHR(0),m.lcBuffer)-1  
  		lnFromPos = AT(CHR(0),m.lcBuffer,m.lnI)  
  		lnToPos = AT(CHR(0),m.lcBuffer,m.lnI+1)  
  		?SubStr(m.lcBuffer,m.lnFromPos+1,m.lnToPos-m.lnFromPos-1)  
  	ENDFOR  
  ENDIF</pre>
<p>Разумеется, объявлять API-функции каждый раз перед записью или чтением значений нет необходимости. Достаточно объявить эти функции один раз в стартовом файле.</p>
<p>Также пример работы с INI-файлами можно посмотреть в классе, поставляемом вместе с FoxPro</p>
<pre class="bbcode">MODIFY CLASS oldinireg OF HOME()+'FFC\registry.vcx'</pre>
<p>Хотя в новейшей идеологии Microsoft предполагается, что вместо ini-файлов следует использовать запись/чтение в системный реестр Windows.</p>
<p>Применительно к FoxPro следует рассмотреть возможность хранения дополнительных настроек в обычном файле DBF, поскольку FoxPro предназначен, прежде всего, именно для работы с файлами DBF.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-rabotat-s-ini-fajlami/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Program]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-proverit-fakt-sushhestvovaniya-peremennoj-pamyati-polya-tabliczy-metoda-formy/</link>
					<title><![CDATA[Как проверить факт существования переменной памяти, поля таблицы, метода формы]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:50:10 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как проверить факт существования переменной памяти, поля таблицы, метода формы</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
Как проверить факт существования переменной памяти, поля таблицы, метода формы и т.п. ?</p></blockquote>
<p><b>Ответ</b></p>
<p>В большинстве случаев такая проверка может быть осуществлена с помощью функции TYPE(). В качестве вычисляемого значения в эту функцию передается тот объект, факт существования которого проверяем. Если в результате получаем значение отличное от "U", то это означает, что такой объект существует.</p>
<p><u><i>Как проверить факт существования переменной памяти</i></u></p>
<pre class="bbcode">IF TYPE("m.MyVar") = "U"  
 	* Переменной памяти с именем MyVar - не существует  
  ENDIF</pre>
<p><u><i>Как проверить факт существования поля таблицы (курсора, View)</i></u></p>
<p>Если таблица (курсор, View) уже открыта в текущей DataSession, то</p>
<pre class="bbcode">IF TYPE("MyTableAlias.MyField") = "U"  
 	* Для таблицы, открытой с алиасом MyTableAlias   
 	* не существует поля с именем MyField  
  ENDIF</pre>
<p>Если таблица включена в контейнер базы данных, то открывать саму таблицу (View) не обязательно. Проверить факт существования нужного поля можно так:</p>
<pre class="bbcode">IF InDBC("MyTable.MyField","FIELD") = .F.  
 	* Для таблицы, включенной в контейнер базы данных под именем MyTable   
 	* не существует поля с именем MyField  
  ENDIF</pre>
<p><u><i>Как проверить факт существования (использования, открытия) формы</i></u></p>
<pre class="bbcode">IF TYPE("_VFP.Forms('MyForm')")="U"  
 	* Формы со свойством name = MyForm не существует (не открыта)  
  ENDIF</pre>
<p>Обратите внимание, что здесь используется системная переменная <b>_VFP</b>. Использовать аналогичный синтаксис с системной переменной <b>_SCREEN</b> - не получиться. Коллекция <b>_SCREEN.Forms()</b> не принимает в качестве параметра символьные значения. Только числовые.</p>
<p>Кроме того, данный способ не сработает для форм, имеющих значение совйства <b>ShowWindow = 2 - As Top-Level Form</b>. В этом случае придется просто перебирать весь массив <b>_SCREEN.Forms()</b> или <b>_VFP.Forms()</b></p>
<pre class="bbcode">LOCAL lnI, loForm  
  loForm = NULL  
  FOR lnI=1 TO _SCREEN.FormCount  
  	loForm = _SCREEN.Forms(m.lnI)  
  	IF m.loForm.Name = "MyForm"  
 		* Нашли форму со свойством Name = "MyForm"  
  		EXIT  
  	ENDIF  
  	loForm = NULL  
  ENDFOR  
  IF IsNull(m.loForm) = .T.  
 	* Формы со свойством name = MyForm не существует (не открыта)  
  ENDIF</pre>
<p><u><i>Как проверить факт существования метода, события или свойства в используемом объекте</i></u></p>
<pre class="bbcode">IF TYPE("_VFP.Forms('MyForm')")="O" AND PEMStatus(_VFP.Forms('MyForm'),'MyMethod',5) = .T.  
 	* Открыта форма со свойством name = MyForm   
 	* и в этой форме существует метод, событие или свойство с именем MyMethod  
  ENDIF</pre>
<p>Для форм, со свойством <b>ShowWindow = 2 - As Top-Level Form</b> данный способ не годится. Придется также перебирать все элементы массива <b>_SCREEN.Forms()</b> как и в предыдущем примере.</p>
<p><u><b>Замечание</b></u></p>
<p>Кроме приведенных способов есть и другие варианты проверки факта существования того или иного объекта. Причем от версии к версии количество способов растет, поскольку появляются все новые команды и функции.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-proverit-fakt-sushhestvovaniya-peremennoj-pamyati-polya-tabliczy-metoda-formy/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Program]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-opredelit-direktoriyu-iz-kotoroj-zapushhena-programma/</link>
					<title><![CDATA[Как определить директорию, из которой запущена программа]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:48:54 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как определить директорию, из которой запущена программа</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
Как определить директорию, из которой запущена готовая программа (файл EXE)</p></blockquote>
<p><b>Ответ</b></p>
<p>В общем случае, этого сделать невозможно! Есть масса способов "сбить с толку" любые команды и функции.</p>
<p>Однако все-таки есть ряд функций, которые могут решить подобную проблему <u>при определенных условиях</u>. Надо всегда помнить, что эти функции не абсолютны. Имеют ограничения.</p>
<pre class="bbcode">  
 * Путь доступа к первой запущенной программе (главному файлу проекта)  
  JustPath(SYS(16,0))  
    
 * Путь доступа к текущей директории  
  FullPath("") - пустая строка (две кавычки подряд) - обязательны  
  SYS(5)+SYS(2003)  
  SET("DEFAULT")+CURDIR()  
  _VFP.DefaultFilePath</pre>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-opredelit-direktoriyu-iz-kotoroj-zapushhena-programma/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Program]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-vosstanovit-povrezhdennuyu-tabliczu/</link>
					<title><![CDATA[Как восстановить поврежденную таблицу]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:45:49 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как восстановить поврежденную таблицу</h1>
													</header>
													<blockquote><p><b>Вопрос</b></p>
<p>Таблица нормально открывалась. Однако после сбоя питания (не корректного выключения компьютера) при открытии таблицы возникает сообщение об ошибке</p></blockquote>
<p>&nbsp;</p>
<blockquote class="bbcode"><p>Цитата:</p>
<div>"file" is not a table (Error 15)</div>
</blockquote>
<p>Как можно починить таблицу?</p>
<p><b>Причина</b></p>
<p>Файл DBF можно рассматривать как обычный текстовый файл. Просто текст. Но такой текст, который имеет определенную внутреннюю структуру. Т.е. любая информация всегда находится по определенному "адресу". В определенном месте этого файла. Грубо говоря, в файле DBF значение вот этого поля из вот этой строки должно находится вот в этом месте.</p>
<p>Что и где должно находится, так сказать, "оглавление", записывается в самом начале файла. В так называемой "заголовочной части". Это просто самое начало файла. После которого идет само содержание файла. Данные.</p>
<p>Естественно "оглавление" должно соответствовать определенному "стандарту", зависящему от версии FoxPro, а также должно соответствовать "содержанию". И некоторые из таких соответствий можно проверить. Т.е. посмотреть действительно ли в указанном месте находится соответствующие данные? Что, собственно, и делает FoxPro при открытии файлов DBF.</p>
<p>Чем старше версия FoxPro, тем большее количество параметров проверяется при открытии файла DBF. Если какой-то параметр не соответствует тем значениям, которые должны быть, то FoxPro выдает сообщение об ошибке</p>
<p><b>Решение</b></p>
<p><b>Прежде чем попытаться "исправить" файл DBF, не важно, каким способом, желательно сделать резервную копию. Пусть и поврежденного файла. Как бы "лечение" не сделало хуже!</b></p>
<p>Помните, что таблица - это совокупность трех файлов с одинковым именем и с расширениями</p>
<p>DBF - собственно таблица<br />
FPT - содержимое мемо-полей<br />
CDX - структурный индексный файл</p>
<p>Это значит, что делать резервную копию надо всех трех файлов. Разумеется, если они есть.</p>
<p>Теоретически, можно самостоятельно проверить соответствие структуры таблицы ее реальному содержанию. В Help по FoxPro достаточно подробно описана структура таблицы и ее заголовочной части. Оглавления. Это статья с названием</p>
<p><a href="http://www.foxclub.ru/rhproject/project/html/465e7a94-51b7-4e0c-98f9-432864fe5bcc.htm" target="_blank" rel="nofollow noopener noreferrer"><u>Table File Structure (.dbc, .dbf, .frx, .lbx, .mnx, .pjx, .scx, .vcx)</u></a></p>
<p>А для мемо-полей, которые хранятся в отдельном файле с расширением FPT это статья с названием</p>
<p><a href="http://www.foxclub.ru/rhproject/project/html/74f53aef-fd56-4f1a-a413-4f045922db21.htm" target="_blank" rel="nofollow noopener noreferrer"><u>Memo File Structure (.FPT)</u></a></p>
<p>Для проверки можно открыть таблицу любым низкоуровневым текстовым редактором. Например, Norton Commander, Disco Commander, FAR-manager и т.п. Далее проанализировать значения в заголовочной части и в области с данными.</p>
<p>Проблема только в том, что при больших размерах файла такой анализ может занять очень много времени. А ручное исправление ошибок очень утомительный процесс.</p>
<p>Тем не менее, просмотреть поврежденный файл в низкоуровневом редакторе бывает полезно. Как правило, при этом можно сделать некоторые общие выводы. Например, а есть ли в файле вообще какая-либо информация. Не заполнен ли файл каким-либо "мусором".</p>
<p>Если стоит задача "спасти" информацию текстового содержания из мемо-полей, то ее можно просто скопировать из файла FPT, поскольку она хранится в нем "как есть". Да и информацию из полей таблицы можно прочитать напрямую. Правда, не всегда "как есть". Иногда требуются некоторые преобразования.</p>
<p>-------------------------------------------------------------------------------------</p>
<p>Есть некоторые способы, позволяющие в простых случаях "привести в чувство" испорченную таблицу.</p>
<p>Если таблицу все-таки удалось открыть, например, отключив проверку структуры настройкой</p>
<pre class="bbcode">SET TABLEVALIDATE TO 0</pre>
<p>Или же открыв таблицу в младшей версии Visual FoxPro. То можно попробовать выполнить следующие действия:</p>
<ol>
<li>При помощи команды COPY TO скопировать содержимое таблицы в другой файл. Команда COPY TO создаст таблицу корректной структуры.</li>
<li>Очистить содержимое испорченной таблицы при помощи команды ZAP или просто пересоздать таблицу заново, если ничто не помогает</li>
<li>Заполнить пустую таблицу командой APPEND FROM данными, сохраненными ранее в копии, при помощи команды COPY TO.</li>
</ol>
<p>Иногда, помогает использование команды PACK.</p>
<p>Если повреждения коснулись ссылок на мемо-поля, то иногда помогает создание нового мемо-поля с последующим его удалением. Дело в том, что факт создания нового мемо-поля заново обновляет все ссылки. Хотя, скорее всего, это приведет к потере данных, записанных в мемо-полях. Но их можно будет достать напрямую, открыв файл FPT как текстовый файл.</p>
<p>--------------------------------------------------------------------------------</p>
<p>Одна из самых распространенных ошибок - это рассогласование реального количества записей и того значения, которое записано в "оглавлении". Среда FoxPro считает, что в таблице находится столько записей, сколько указано в "оглавлении" этой таблицы.</p>
<p>Если в старших версиях FoxPro это рассогласование вызовет сообщение об ошибке в момент открытия, то в младших версиях FoxPro это соответствие не проверяется. Как следствие, при открытии таблицы Вы увидите меньше записей, чем есть на самом деле. Или больше. Но в последнем случае, эти "лишние" записи будут заполнены "мусором".</p>
<p>Собственно, довольно просто проверить это соответствие самостоятельно. Достаточно посмотреть, как именно формируется "оглавление" в файле DBF. Т.е. посмотреть в HELP структуру файла DBF. Или поискать в интернете различные "фиксеры", которые исправляют некоторые повреждения структуры файла DBF.</p>
<p>Только следует с осторожностью использовать "фиксеры" найденные в интернете. Учитывая тот факт, что есть отличия в структурах файлов DBF для FoxPro 2.x и Visual FoxPro. Отличия в структуре файлов DBF разных версий Visual FoxPro можно считать не существенным с точки зрения исправления возможных повреждений структуры. Впрочем, и большинство "фиксеров" разработанных для FoxPro 2.x могут успешно исправить и повреждение таблиц Visual FoxPro.</p>
<p>Еще раз напомню, прежде чем попытаться "исправить" файл DBF при помощи сторонней утилиты, желательно сделать резервную копию. Пусть и поврежденного файла. Как бы "лечение" не сделало хуже!</p>
<p>-------------------------------------------------------------------------</p>
<p>Ниже приведен один из вариантов исправления</p>
<pre class="bbcode">  
 *********************************************************************  
 * Назначение : 	Приведение в соответствие значение количества записей   
 *		в заголовке таблице и реального количества записей  
 * Автор : 	Владимир Максимов  
 * Дата : 	31.08.2008  
 * Версия FoxPro: Visual FoxPro с 3 по 9  
 *		Возможно, этот код будет работать и в версиях FoxPro 2.x  
 *		если убрать объявления LOCAL и MessageBox()   
 *		Но это не проверялось  
 *********************************************************************  
    
 * Пользователь выбирает файл для проверки  
 * 5 параметр в функции GetFile() был введен только в версии Visual FoxPro 6  
 * для младших версий FoxPro его надо удалить  
  Local lcFileName  
  lcFileName = GetFile("DBF","","",0,"Выбор файла для проверки количества записей")  
  If Empty(m.lcFileName)  
 	* Файл не был выбран  
  	Return  
  EndIf  
    
 * Открываю файл и запоминаю его дескриптор (идентификатор)  
  Local lnFD  
  lnFD = Fopen(m.lcFileName,12)  
  If m.lnFD &lt; 0  
  	MessageBox("Не удалось открыть файл" + Chr(13) + ;  
  		m.lcFileName + Chr(13) + ;  
  		"Возможно, он открыт другим приложением")  
  EndIf  
    
 * Теоретически, здесь хорошо бы добавить проверку на тот факт,   
 * что данный файл - это DBF-таблица (анализ первого байта)  
 * Но в данном случае предполагается, что пользователь понимает, что он делает  
 * Если, тем не менее, Вы хотите создать универсальную утилиту, то  
 * посмотрите код программы CPZERO.PRG из поставки FoxPro.  
 * Эта программа находится в каталоге TOOLS\CPZERO корневой папки FoxPro  
    
 * Определяю количество записей записанное в заголовке файла  
 * байты с 4 по 7  
  LOCAL lnReccount  
  =FSEEK(m.lnFD,4)  
  lnReccount =	ASC(FREAD(m.lnFD,1)) + ;  
  		ASC(FREAD(m.lnFD,1)) * 256 + ;  
  		ASC(FREAD(m.lnFD,1)) * 256 * 256 + ;  
  		ASC(FREAD(m.lnFD,1)) * 256 * 256 * 256  
  			  
 * Определяю позицию, с которой начинается собственно данные (первая запись)  
 * байты с 8 по 9  
  LOCAL lnDataStart  
  lnDataStart = 	ASC(FREAD(m.lnFD,1)) + ;  
  		ASC(FREAD(m.lnFD,1)) * 256  
    
 * Определяю количество символов в одной записи, включая метку на удаление  
 * байты с 10 по 11  
  LOCAL lnRecLength  
  lnRecLength =	ASC(FREAD(m.lnFD,1)) + ;  
  		ASC(FREAD(m.lnFD,1)) * 256  
    
 * Определяю общий размер файла, через порядковый номер последнего байта  
  LOCAL lnFileSize  
  =FSEEK(m.lnFD,0,0)  
  lnFileSize = FSEEK(m.lnFD,0,2)  
    
 * Определяю значение самого последнего байта файла  
  LOCAL lnEndByte  
  =FSEEK(m.lnFD,-1,1)  
  lnEndByte = ASC(FREAD(m.lnFD,1))  
    
 * И реальное количество записей в файле  
  LOCAL lnFaktCount  
  DO CASE  
  CASE m.lnFileSize = m.lnDataStart  
 	* Т.е. в таблице вообще нет информации  
  	lnFaktCount = 0  
  CASE m.lnEndByte = 26  
 	* Если последний байт файла имеет ASCII код 26 (0x1A),   
 	* то общее число информационных байтов надо уменьшить на 1  
  	lnFaktCount = (m.lnFileSize - m.lnDataStart - 1) / m.lnRecLength  
  OTHERWISE  
  	lnFaktCount = (m.lnFileSize - m.lnDataStart) / m.lnRecLength  
  ENDCASE  
    
    
  LOCAL lnResult  
 * Анализ полученных результатов  
  DO CASE  
  CASE INT(m.lnFaktCount) &lt;&gt; m.lnFaktCount  
    
 	* Есть дробная часть. Т.е. выделить целое количество записей невозможно  
 	* повреждения более существенные, чем разница в количестве записей  
 	* лучше ничего не трогать  
  	lnResult = -1  
  	=Fclose(m.lnFD)  
  	  
  	MessageBox("Выделить целое количество записей невозможно"+Chr(13) + ;  
  				"Повреждения более существенные, чем разница в количестве записей")  
    
  CASE m.lnFaktCount &lt;&gt; m.lnReccount  
    
 	* Записанное и фактическое количество записей отличаются  
 	* корректирую записанное количество записей  
  	=FSEEK(m.lnFD,4,0)  
  	FOR lnI=1 TO 4  
  		=FWRITE(m.lnFD,CHR(MOD(INT(m.lnFaktCount / 256**(m.lnI-1)),256)))  
  	ENDFOR  
    
  	lnResult = 1  
  	=Fclose(m.lnFD)  
    
  	MessageBox("Значение количества записей исправлено")  
    
  OTHERWISE  
    
 	* Ошибки в определении количества записей не обнаружено  
  	lnResult=0  
  	=Fclose(m.lnFD)  
    
  	MessageBox("Ошибки в количестве записей не обнаружено")  
    
  ENDCASE  
    
 * Результат возвращается на случай, если есть необходимость в подобном анализе  
  RETURN m.lnResult</pre>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-vosstanovit-povrezhdennuyu-tabliczu/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с данными]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-poluchit-programmnyj-kod-sozdaniya-struktury-bazy-dannyh/</link>
					<title><![CDATA[Как получить программный код создания структуры базы данных]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Sat, 29 Aug 2020 18:43:57 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как получить программный код создания структуры базы данных</h1>
													</header>
													<blockquote><p><b>Вопрос</b><br />
Как я могу получить (посмотреть) программный код создания структуры базы данных</p></blockquote>
<p><b>Ответ</b></p>
<p>Вместе с FoxPro поставляется утилита (программа) по генерации программного кода структуры существующей базы данных. Она называется GenDBC.prg</p>
<p>В командном окне FoxPro дайте команду</p>
<pre class="bbcode">DO (HOME()+"Tools\GenDBC\GenDBC.prg")</pre>
<p>Скобки в данном случае обязательны</p>
<p>Сначала Вам будет предложено указать контейнер базы данных (файл DBC), структуру которого Вы хотите получить.</p>
<p>Следующим шагом Вас попросят указать имя файла PRG, куда будет записана полученная структура.</p>
<p>В результате работы данной утилиты, Вы получите файл PRG, который можно просмотреть из среды FoxPro через стандартную команду</p>
<pre class="bbcode">MODIFY COMMAND</pre>
<p>Запуск данного файла на исполнение создаст структуру базы данных полностью идентичную тому контейнеру базы данных, который был использован в качестве образца. Разумеется, пустую. Без самих данных.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-poluchit-programmnyj-kod-sozdaniya-struktury-bazy-dannyh/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с данными]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pri-rabote-v-seti-inogda-ne-otkryvaetsya-tablicza/</link>
					<title><![CDATA[При работе в сети иногда не открывается таблица]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 11:13:20 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>При работе в сети иногда не открывается таблица</h1>
													</header>
													<blockquote><p><b>Проблема</b></p>
<p>В сетевом приложении при одновременной работе нескольких пользователей иногда не открываются таблицы. Возникает сообщение вроде  <em>"Attempting to lock... Press Esc to cancel"</em></p></blockquote>
<p><b>Причина</b></p>
<p>Это связано с ужесточением контроля структуры таблиц в момент их открытия, начиная с версии Visual FoxPro 8. Варианты этого контроля регулируются настройкой</p>
<pre class="bbcode">SET TABLEVALIDATE</pre>
<p>На момент проведения такого контроля (при открытии таблицы) требуется заблокировать заголовок таблицы. Если это невозможно (заголовок блокирован другим пользователем), то и возникает данное сообщение.</p>
<p><b>Решение</b></p>
<p>В принципе, Вы, конечно, можете снизить уровень контроля, изменив настройку SET TABLEVALIDATE. Однако более корректным является изменение самой логики построения многопользовательского приложения.</p>
<p>Основная идея изменения логики заключается в уменьшении времени блокировки как заголовка таблицы (что необходимо в данном случае), так и каких-либо блокировок в таблицах вообще. Т.е. недопустимо давать команду типа FLOCK() на неопределенно долгое время, ожидая реакции пользователя. Или использовать пессимистическую буферизацию.</p>
<p>Блокировка должна осуществляться только в момент сохранения внесенных изменений и в этот момент недопустимо ожидание реакции пользователя.</p>
<p>Разумеется, такая идеология построения многопользовательского приложения при неизменном уровне контроля SET TABLEVALIDATE не устранит данную проблему совсем, но существенно снизит как вероятность ее появления, так и вероятность повреждения таблиц в случае аварийного отключения питания.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pri-rabote-v-seti-inogda-ne-otkryvaetsya-tablicza/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с данными]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/zapros-s-group-by-vydaet-soobshhenie-o-sintaksicheskoj-oshibke/</link>
					<title><![CDATA[Запрос с GROUP BY выдает сообщение о синтаксической ошибке]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 11:09:47 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Запрос с GROUP BY выдает сообщение о синтаксической ошибке</h1>
													</header>
													<p><b>Проблема</b></p>
<p>Я выполняю примерно такой запрос</p>
<pre class="bbcode">SELECT company, country FROM Customer GROUP BY country</pre>
<p>И в версии FoxPro начиная с 8 и выше, получаю сообщение вроде</p>
<blockquote class="bbcode"><p>Цитата:</p>
<div>SQL: GROUP BY clause is invalid (Error 1807)</div>
</blockquote>
<p>Причем в младших версиях FoxPro подобный запрос работал без проблем.</p>
<p><b>Причина</b></p>
<p>Начиная с версии Visual FoxPro 7.0, были ужесточены требования к корректности конструкции SQL-запросов.</p>
<p>В данном случае запрос содержит неоднозначность: Какое именно значение поля <i>company</i> надо взять из таблицы, если для одного и того же значения <i>country</i> их может существовать несколько?</p>
<p>В младших версиях FoxPro в этом случае использовалось первое попавшееся значение. В старших версиях FoxPro такая конструкция воспринимается как синтаксически некорректная.</p>
<p><b>Решение</b></p>
<p>Следует перечислить в конструкции GROUP BY все поля результирующей выборки, которые не имеют агрегирующих функций</p>
<pre class="bbcode">SELECT company, country FROM Customer GROUP BY company, country</pre>
<p>или добавить любую агрегирующую функцию к тем полям, которые не перечислены в конструкции GROUP BY</p>
<pre class="bbcode">SELECT MAX(company) as company, country FROM Customer GROUP BY country</pre>
<p>Впрочем, если Вы переводите свое приложение со старой версии FoxPro в новую версию, то можно явно указать FoxPro, что нужно использовать старые правила разбора и выполнения SQL-запроса при помощи настройки</p>
<pre class="bbcode">SET ENGINEBEHAVIOR 70</pre>
<p>Однако, по возможности, все-таки лучше придерживаться стандартных правил составления запросов в том смысле, что в конструкции GROUP BY должны быть перечислены все поля, которые не участвуют в агрегирующих функциях.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/zapros-s-group-by-vydaet-soobshhenie-o-sintaksicheskoj-oshibke/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с данными]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-izmenit-znacheniya-v-odnoj-tablicze-dannymi-iz-drugoj/</link>
					<title><![CDATA[Как изменить значения в одной таблице данными из другой]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 11:08:45 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как изменить значения в одной таблице данными из другой</h1>
													</header>
													<blockquote><p><b>Задача</b></p>
<p>Есть две таблицы связанные отношением один-к-одному по содержимому ключевых полей. Как можно изменить значения в поле главной таблицы на значение поля подчиненной таблицы из соответствующей записи?</p></blockquote>
<p><b>Решение</b></p>
<p>Исходные данные</p>
<pre class="bbcode">  
 * Главная таблица    
  CREATE CURSOR tabMain (tabMainID I, Summa N(18,2))  
  INDEX ON tabMainID TAG tabMainID  
  SET ORDER TO 0  
  INSERT INTO tabMain (tabMainID, Summa) VALUES (1, 0)  
  INSERT INTO tabMain (tabMainID, Summa) VALUES (2, 0)  
  INSERT INTO tabMain (tabMainID, Summa) VALUES (3, 0)  
    
 * Подчиненная таблица    
  CREATE CURSOR tabChild (tabChildID I, tabMainID I, Qty I, Price N(18,2))  
  INDEX ON tabMainID TAG tabMainID  
  SET ORDER TO 0  
  INSERT INTO tabChild (tabChildID, tabMainID, Qty, Price) VALUES (1, 1, 10, 0.25)  
  INSERT INTO tabChild (tabChildID, tabMainID, Qty, Price) VALUES (2, 2, 15, 10.05)  
  INSERT INTO tabChild (tabChildID, tabMainID, Qty, Price) VALUES (3, 3, 30, 5.00)</pre>
<p>Способ решения отличается для версии Visual FoxPro 9 и младших версий, поскольку в 9 версии значительно расширены возможности команды Select-SQL</p>
<pre class="bbcode">  
 * Для версии младше Visual FoxPro 9  
  SELECT tabMain  
  REPLACE FOR SEEK(tabMain.tabMainID,"tabChild","tabMainID") ;  
  	Summa WITH tabChild.Qty*tabChild.Price  
    
 * Или через команду UPDATE  
  UPDATE tabMain SET Summa = tabChild.Qty*tabChild.Price ;  
  	WHERE SEEK(tabMain.tabMainID,"tabChild","tabMainID")   
    
 * Для Visual FoxPro 9  
  UPDATE tabMain ;  
  SET Summa =tabChild.Qty*tabChild.Price ;  
  FROM tabChild ;  
  WHERE tabMain.tabMainID=tabChild.tabMainID</pre>
<p>Если дочерняя таблица не имеет нужного индекса, то для версии младше Visual FoxPro 9 остается только сканирование главной таблицы с поиском нужной записи в подчиненной таблице через команду LOCATE</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-izmenit-znacheniya-v-odnoj-tablicze-dannymi-iz-drugoj/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с данными]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-vypolnit-vosstanovlenie-povrezhdennyh-indeksov/</link>
					<title><![CDATA[Как выполнить восстановление поврежденных индексов]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 11:06:54 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как выполнить восстановление поврежденных индексов</h1>
													</header>
													<blockquote><p><b>Вопрос</b></p>
<p>Как выполнить восстановление поврежденных индексов</p></blockquote>
<p><b>Ответ</b></p>
<p>В версии FoxPro 2.x стандартным советом было: удалите все индексы и создайте их заново.</p>
<p>Однако с появление контейнера базы данных в Visual FoxPro последовать данному совету крайне затруднительно. Проблема в том, что кроме собственно создания файлов CDX потребуется еще восстановить ряд реквизитов внутри контейнера базы данных. В принципе, можно сделать и это. Но есть более простой способ.</p>
<ol>
<li>Предварительно Вам необходимо создать резервную копию структуры Вашей базы данных. Т.е. вообще все файлы DBF, CDX, FPT, DBC, DCT, DCX, но без собственно данных. Пустые таблицы. В данном случае также подойдет резервная копия Вашей базы данных. Т.е. заполненные данные за предыдущий период. Главное, чтобы эта копия имела не поврежденные индексные файлы.</li>
<li>В случае повреждения индексов, все файлы CDX просто удаляются из рабочей базы данных. На их место копируются одноименные файлы из резервной копии.</li>
<li>Поскольку структура файлов CDX в резервной копии не повреждена, то Вы сможете открыть Ваши таблицы в эксклюзивном (единоличном) режиме без проблем. Т.е. без сообщений об ошибках.
<pre class="bbcode">USE MyTab.dbf EXCLUSIVE</pre>
</li>
<li>Теперь остается только привести в соответствие содержимое индексных файлов и собственно таблиц. Для этого следует использовать команду
<pre class="bbcode">REINDEX</pre>
</li>
</ol>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-vypolnit-vosstanovlenie-povrezhdennyh-indeksov/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с данными]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/vybrat-zapisi-s-povtoryayushhimisya-dubliruyushhimi-znacheniyami-polya/</link>
					<title><![CDATA[Выбрать записи с повторяющимися (дублирующими) значениями поля]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 11:05:11 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Выбрать записи с повторяющимися (дублирующими) значениями поля</h1>
													</header>
													<blockquote><p><b>Задача</b></p>
<p>Есть одна таблица. В одном из ее полей могут содержаться повторяющиеся значения. Т.е. разные записи этой таблицы могут иметь одно и то же значение в этом поле. Как выбрать все записи, в которых имеются повторяющиеся (дублирующие) значения в этом поле.</p></blockquote>
<p><b>Решение</b></p>
<pre class="bbcode">  
 * Исходная таблица    
  CREATE CURSOR tabMain (tabMainID I, NickName C(50), curDate D, Chet L)  
  INSERT INTO tabMain (tabMainID, NickName, curDate, Chet) VALUES (1, "Первая запись", Date(2005,6,1), .F.)  
  INSERT INTO tabMain (tabMainID, NickName, curDate, Chet) VALUES (2, "Вторая запись", Date(2005,6,2), .T.)  
  INSERT INTO tabMain (tabMainID, NickName, curDate, Chet) VALUES (3, "Третья запись", Date(2005,6,3), .F.)  
  INSERT INTO tabMain (tabMainID, NickName, curDate, Chet) VALUES (4, "Четвертая запись", Date(2005,6,1), .T.)  
  INSERT INTO tabMain (tabMainID, NickName, curDate, Chet) VALUES (5, "Пятая запись", Date(2005,6,2), .F.)  
  INSERT INTO tabMain (tabMainID, NickName, curDate, Chet) VALUES (6, "Шестая запись", Date(2005,6,1), .T.)</pre>
<p>У функции DATE() можно задавать параметры, начиная с версии Visual FoxPro 6. Для младших версий укажите значение даты другим способом.</p>
<p>Находим все записи, у которых повторяется значение поля curDate</p>
<pre class="bbcode">  
  SELECT DISTINCT tabMain.* ;    
  FROM tabMain ;    
  INNER JOIN tabMain tabDouble ON tabMain.curDate = tabDouble.curDate  ;    
    			AND tabMain.tabMainID &lt;&gt; tabDouble.tabMainID ;  
  ORDER BY tabMain.curDate</pre>
<p>Следует иметь в виду, что данное решение опирается на тот факт, что у таблицы есть уникальное (не повторяющееся) ключевое поле tabMainID.</p>
<p>Кроме того, данное решение легко расширить для случая, если требуется отобрать записи по повторяющемуся значению в нескольких полях. Достаточно просто добавить дополнительное условие через AND в условие объединения таблицы.</p>
<p>Например, найти все записи, у которых повторяется как значение поля curDate, так и значение поля Chet.</p>
<pre class="bbcode">  
  SELECT DISTINCT tabMain.* ;    
  FROM tabMain ;    
  INNER JOIN tabMain tabDouble ON tabMain.curDate = tabDouble.curDate  ;    
    			AND tabMain.Chet = tabDouble.Chet ;  
    			AND tabMain.tabMainID &lt;&gt; tabDouble.tabMainID ;  
  ORDER BY tabMain.curDate, tabMain.Chet</pre>
<p>Если у Вас стоит более простая задача: определить просто список значений, которые встречаются в таблице более одного раза, то это можно сделать проще.</p>
<p>Определяю значение поля curDate, которое встречается более одного раза</p>
<pre class="bbcode">  
  SELECT tabMain.curDate  ;    
  FROM tabMain ;    
  GROUP BY tabMain.curDate ;  
  HAVING count(*) &gt; 1</pre>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/vybrat-zapisi-s-povtoryayushhimisya-dubliruyushhimi-znacheniyami-polya/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с данными]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/vybrat-iz-dochernej-tabliczy-zapisi-s-maksimalnoj-datoj/</link>
					<title><![CDATA[Выбрать из дочерней таблицы записи с максимальной датой]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 11:03:59 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Выбрать из дочерней таблицы записи с максимальной датой</h1>
													</header>
													<blockquote><p><b>Задача</b></p>
<p>Есть 2 таблицы (главная и подчиненная) связанные отношением один-ко-многим. Одно из полей подчиненной таблицы - это дата. Необходимо для каждой записи главной таблицы выбрать одну запись из подчиненной таблицы с максимальным значением даты. Т.е. не просто определить максимальную дату, а выбрать всю запись с этой максимальной датой</p></blockquote>
<p><b>Решение</b></p>
<p>Исходные данные</p>
<pre class="bbcode">  
 * Главная таблица  
  CREATE CURSOR tabMain (tabMainID I, NickName C(50))    
  INSERT INTO tabMain (tabMainID, NickName) VALUES (1, "Первая запись главной таблицы")    
  INSERT INTO tabMain (tabMainID, NickName) VALUES (2, "Вторая запись главной таблицы")    
  INSERT INTO tabMain (tabMainID, NickName) VALUES (3, "Третья запись главной таблицы")    
    
 * Подчиненная таблица  
 * Для первой записи главной таблицы есть дублирующее значение по максимальной дате  
 * Для второй записи главной таблицы вообще нет значений в подчиненной таблице  
  CREATE CURSOR tabChild (tabChildID I, tabMainID I, CurDate D, NickName C(50))    
  INSERT INTO tabChild (tabChildID, tabMainID, CurDate, NickName) ;  
  	VALUES (1, 1, DATE(2005,6,15), "Первая запись дочерней первой записи главной")  
  INSERT INTO tabChild (tabChildID, tabMainID, CurDate, NickName) ;  
  	VALUES (2, 1, DATE(2005,6,15), "Вторая запись дочерней первой записи главной")  
  INSERT INTO tabChild (tabChildID, tabMainID, CurDate, NickName) ;  
  	VALUES (3, 1, DATE(2005,6,10), "Третья запись дочерней первой записи главной")  
  INSERT INTO tabChild (tabChildID, tabMainID, CurDate, NickName) ;  
  	VALUES (4, 3, DATE(2005,6,13), "Первая запись дочерней третьей записи главной")  
  INSERT INTO tabChild (tabChildID, tabMainID, CurDate, NickName) ;  
  	VALUES (5, 3, DATE(2005,6,14), "Первая запись дочерней третьей записи главной")</pre>
<p>У функции DATE() можно задавать параметры, начиная с версии Visual FoxPro 6. Для младших версий укажите значение даты другим способом.</p>
<p>Наиболее очевидным кажется решение через поиск максимального значения. Примерно так</p>
<pre class="bbcode">  
  SELECT tabMain.*, tabChild.* ;  
  FROM tabMain ;  
  INNER JOIN tabChild ON tabMain.tabMainID=tabChild.tabMainID ;  
  WHERE tabChild.CurDate IN ;  
  	(SELECT MAX(CurDate) FROM tabChild WHERE tabMainID = tabMain.tabMainID)</pre>
<p>Однако если в дочерней таблице есть записи с одинаковым значением даты и эти даты являются максимальными, то в результирующей выборке получим лишние записи. Попробуйте выполнить этот запрос для приведенных исходных данных и вы увидите в чем проблема.</p>
<p>Чтобы исключить отбор подобных "дублей" следует опираться на уникальный идентификатор записи. В данном случае это tabChild.tabChildID. С его помощью следует отделить одну запись от другой с одинаковой датой.</p>
<p>При этом, чтобы задействовать механизмы оптимизации следует отойти от "шаблона" поиска максимального значения. Точнее, следует вспомнить, что "максимальное" означает лишь тот факт, что нет значения больше, чем найденное. Это значит, что функцию MAX() можно заменить на сравнение "больше или меньше".</p>
<pre class="bbcode">  
  SELECT tabMain.*, tab2.* ;  
  FROM tabMain ;  
  INNER JOIN tabChild tab2 ON tabMain.tabMainID=tab2.tabMainID ;  
  WHERE NOT EXISTS(SELECT 'x' FROM tabChild ;  
  		WHERE tab2.tabMainID = tabChild.tabMainID ;  
  			AND tab2.CurDate &lt; tabChild.CurDate) ;  
  AND NOT EXISTS(SELECT 'x' FROM tabChild ;  
  		WHERE tab2.tabMainID = tabChild.tabMainID ;  
  			AND tab2.CurDate = tabChild.CurDate ;  
  			AND tab2.tabChildId &lt; tabChild.tabChildId)</pre>
<p>Разберем этот запрос подробнее.</p>
<p>Первое объединение по INNER JOIN просто связывает главную и подчиненную таблицу. Получим все записи подчиненной таблицы, соответствующие записям главной таблицы.</p>
<p>Теперь из этих записей надо оставить лишь те, дата в которых максимальная. Т.е. не существует записей (NOT EXISTS), которые также относились бы к той же записи главной таблицы и имели бы дату бОльшую, чем в найденной записи. Именно это и делает первый подзапрос.</p>
<p>А вот что делает второй подзапрос? Он предназначен именно для контроля той ситуации, когда в дочерней таблице могут быть записи с одинаковым значением даты. В данном случае, в случае наличия такой ситуации в выборку попадут только записи, имеющие бОльшее значение идентификатора записи. Но вы можете указать символ "больше", тогда будет отбираться запись имеющая меньшее значение идентификатора записи.</p>
<p>Обратите внимание, что здесь нельзя использовать для сравнения ключевых полей "не равно". Поскольку "не равно" будет справедливо для обоих записей с одинаковой датой.</p>
<p>К сожалению, в Visual FoxPro невозможно объединить эти два подзапроса в один. Впрочем, в таком виде запрос выглядит более наглядно. А если вы уверены, что в вашей таблице не может быть записей с одинаковым значением даты, то просто не включайте второй подзапрос.</p>
<p>В принципе, тот же самый алгоритм можно использовать, если надо найти не максимальную дату, а скажем, максимальную цену. Или максимальную сумму.</p>
<p>Если вы хотите получить в выборке все записи главной таблицы вне зависимости от того, есть ли для них хотя бы одна запись в подчиненной таблице, то достаточно заменить "INNER JOIN" на "LEFT JOIN" больше ничего не меняя в запросе.</p>
<p>===================================================================================</p>
<p>Есть еще одно, довольно экзотическое, решение. Оно заведомо не оптимизируемо, поэтому выполняется достаточно медленно.</p>
<p>Способ решения отличается для версии Visual FoxPro 9 и младших версий, поскольку в 9 версии значительно расширены возможности команды Select-SQL</p>
<pre class="bbcode">  
 * Для версии младше Visual FoxPro 9  
    
  SELECT tabMain.*, tabChild.* ;  
  FROM tabMain ;  
  INNER JOIN tabChild ON tabMain.tabMainID=tabChild.tabMainID ;  
  WHERE tabChild.tabChildID IN ;  
  	(SELECT CTOBIN(RIGHT(MAX(DTOS(CurDate)+BINTOC(tabChildID)),4)) ;  
  			FROM tabChild GROUP BY tabMainID) ;  
  UNION ALL ;  
  SELECT tabMain.*, 0, 0, {}, '' ;  
  FROM tabMain ;  
  WHERE tabMain.tabMainID NOT IN (SELECT tabMainID FROM tabChild)  
    
 * Для Visual FoxPro 9  
    
  SELECT tabMain.*, tabChild.* ;  
  FROM tabMain ;  
  LEFT JOIN tabChild ON tabMain.tabMainID=tabChild.tabMainID ;  
  WHERE tabChild.tabChildID IS NULL ;  
  	OR tabChild.tabChildID IN ;  
  		(SELECT CTOBIN(RIGHT(MAX(DTOS(CurDate)+BINTOC(tabChildID)),4)) ;  
  			FROM tabChild GROUP BY tabMainID)</pre>
<p>Основная идея заключается в том, что в подзапросе ищется не просто значение максимальной даты, а некоего "синтетического" ключа. Суммы строк даты и ключевого поля дочерней таблицы.</p>
<p>Для корректного определения максимального значения дата конвертируется в строку при помощи функции DTOS(). Т.е. это представления даты в виде "ГГГГММДД". Другими словами дата "15 июня 2005 года" будет выглядеть как "20050615".</p>
<p>В данном примере, ключевое поле дочерней таблицы имеет тип Integer. Для конвертации его в строку использована функция BINTOC() просто для того, чтобы получить как можно меньший размер. В данном случае получается строка длиной в 4 символа. А в случае стандартного преобразования через STR() пришлось бы выделить 10 символов. Отсечь ведущие пробелы в данном случае нельзя.</p>
<p>Найденное максимальное значение по такому выражению, по сути, означает, что в пределах одного значения поля tabMainID найдена запись с максимальным значением даты, а если существуют несколько записей с максимальным значением даты, то среди них отбирается запись с максимальным значением ключевого поля tabChilID.</p>
<p>После того, как будет найдено максимальное значение для такого "синтетического" ключа из него выделяются последние 4 символа и преобразуются к типу Integer. По сути, получаем значение кода записи дочерней таблицы для максимального значения даты.</p>
<p>Далее уже все просто. Используя конструкцию IN, отбираем нужные записи дочерней таблицы. Ну, а объединение нужно в том случае, если требуются еще данные из главной таблицы.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/vybrat-iz-dochernej-tabliczy-zapisi-s-maksimalnoj-datoj/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с данными]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/pochemu-vozvrashhaetsya-tolko-chast-chisla-pervye-simvoly/</link>
					<title><![CDATA[Почему возвращается только часть числа. Первые символы]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 10:59:26 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Почему возвращается только часть числа. Первые символы</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>При чтении числовых данных с SQL-сервера возвращается только часть числа. Первые символы или только целая часть без дробной части.</p>
<p><b>Причина</b></p>
<p>Причина в настройках конкретного соединения с SQL-сервера. Явно или не явно установлены региональные настройки. Обратите внимание, речь идет не о настройках собственно сервера, а о настройках соединения с сервером!</p>
<p>Проблема здесь в том, что числовые данные как правило, конвертируются в поля типа Numeric в среде FoxPro. А поля типа Numeric в FoxPro физически хранятся как символьные данные. Это значит, что в принципе, в такое поле можно записать любой символ. Вот ODBC и записал, например, символ запятой в соответствии с региональной настройкой.</p>
<p>Но при чтении данных для FoxPro символ запятой - это не есть символ, относящийся к числовым данным (символом-разделителем целой и дробной части непосредственно в таблице является точка). Следовательно, будут прочитаны как число только те символы, которые стоят ДО символа запятой.</p>
<p><b>Решение</b></p>
<p>Решение зависит от того, каким способом были установлены соответствующие настройки соединения.</p>
<p><u><b>MS SQL - сервер</b></u></p>
<p>Если Вы использовали для установки соединения предварительно настроенный DSN, то зайдите в настройки DSN-соединения и снимите "птичку" с настройки</p>
<p>"<b>Use regional settings when outputting currency, numbers, dates, and times</b>"</p>
<p>Если Вы использовали для установки соединения строку SQLStringConnect(), то убедитесь, что в ней нет опции Regional или же она имеет значение Regional=No</p>
<p><u><b>Oracle - сервер</b></u></p>
<p>Здесь придется явным образом менять настройку текущей сессии через прямую команду SQLExec() примерно так</p>
<pre class="bbcode">SQLExec(m.nOraConnect,[ALTER SESSION SET NLS_NUMERIC_CHARACTERS='. '])</pre>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/pochemu-vozvrashhaetsya-tolko-chast-chisla-pervye-simvoly/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с удаленными данными или SQL-серверами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-poluchit-znachenie-funkczii-servera/</link>
					<title><![CDATA[Как получить значение функции сервера]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 10:58:34 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как получить значение функции сервера</h1>
													</header>
													<p><b>Вопрос</b></p>
<p>Как получить значение, возвращаемое моей функцией, написанной на SQL-сервере?</p>
<p><b>Ответ</b></p>
<p>Для этого используют специальную синтаксическую конструкцию</p>
<pre class="bbcode">  
  LOCAL lnReturnValue  
  lnReturnValue = 0  
  SQLEXEC(m.lnHandle,"{?@lnReturnValue= Call MyFunction()}")   
  ?lnReturnValue</pre>
<p>По аналогии с чтением значения параметров OUTPUT</p>
<p><b>Замечание</b></p>
<p>Данный прием не сработает для внутренних функций MS SQL. Т.е. таким образом невозможно будет получить значение, например, функции SCOPE_IDENTITY().</p>
<p>Для внутренних функций MS SQL следует использовать штатный механизм возвращения результатов запроса:</p>
<pre class="bbcode">  
  SQLEXEC(m.lnHandle,"SELECT SCOPE_IDENTITY() as LastIdent","tabLastIdent")   
  ?tabLastIdent.LastIdent</pre>
<p>&nbsp;</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-poluchit-znachenie-funkczii-servera/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с удаленными данными или SQL-серверами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-poluchit-znachenie-vyhodnogo-parametra-proczedury-servera/</link>
					<title><![CDATA[Как получить значение выходного параметра процедуры сервера]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 10:57:36 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как получить значение выходного параметра процедуры сервера</h1>
													</header>
													<p><b>Вопрос</b></p>
<blockquote><p>
На SQL-сервере создана процедура, имеющая выходной параметр. Т.е. параметр, имеющий признак OUTPUT. Как прочитать возвращаемое значение этого параметра.</p></blockquote>
<p><b>Ответ</b></p>
<p>Синтаксис будет почти такой же, как и при передаче параметра в хранимую процедуру. Подробно это описано в статье "<a href="http://forum.foxclub.ru/read.php?32,186265,186272#msg-186272" target="_blank" rel="nofollow noopener noreferrer"><u>Как передать параметры в хранимую процедуру сервера</u></a>"</p>
<p>Отличие заключается только в том, что используется не один символ вопросительного знака, а два символа: вопросительный знак и @.</p>
<pre class="bbcode">  
  LOCAL lnPar1, lcPar2    
  lnPar1 = 123.456    
  lcPar2 = ""  &amp;&amp; В эту переменную будет записано значение параметра OUTPUT  
  SQLExec(lnHandle,"{Call MyProc (?m.lnPar1, ?@m.lnPar2)}")</pre>
<p>Разумеется, для конкретного SQL-сервера, кроме общего вызова через CALL, можно использовать вызов через соответствующие синтаксические конструкции конкретного сервера. Например, для MS SQL сервера можно использовать вызов через EXECUTE</p>
<pre class="bbcode">  
  LOCAL lnPar1, lcPar2    
  lnPar1 = 123.456    
  lcPar2 = ""  &amp;&amp; В эту переменную будет записано значение параметра OUTPUT  
  SQLExec(lnHandle,"Execute MyProc ?m.lnPar1, ?@m.lnPar2")</pre>
<p><b>Замечание</b></p>
<blockquote><p>
Не используйте в качестве параметра переменные памяти с именем, состоящем из одной буквы. В этом случае такая конструкция может не сработать, поскольку в синтаксисе FoxPro за многими буквами закреплены имена рабочих областей. Например, буква "a" - это первая рабочая область.</p></blockquote>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-poluchit-znachenie-vyhodnogo-parametra-proczedury-servera/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с удаленными данными или SQL-серверами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-peredat-parametry-v-hranimuyu-proczeduru-servera/</link>
					<title><![CDATA[Как передать параметры в хранимую процедуру сервера]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 10:56:17 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как передать параметры в хранимую процедуру сервера</h1>
													</header>
													<p><b>Вопрос</b></p>
<blockquote><p>В пользовательской форме были сформированы некоторые значения. Как передать эти сформированные значения в качестве параметров в хранимую процедуру сервера?</p></blockquote>
<p><b>Ответ</b></p>
<p>Для передачи значения как параметра в синтаксисе FoxPro используется вопросительный знак.</p>
<pre class="bbcode">  
  LOCAL lnPar1, lcPar2  
  lnPar1 = 123.456  
  lcPar2 = "Новое значение"  
  SQLExec(lnHandle,"{Call MyProc (?m.lnPar1, ?m.lnPar2)}")</pre>
<p>Все то, что следует за символом вопросительного знака до первого пробела или запятой - это параметр. Конвертация в тип, понятный SQL-серверу произойдет автоматически. Никаких дополнительных преобразований делать не надо.</p>
<p>В качестве параметра можно использовать не только переменные памяти, но и поля таблицы и объекты формы.</p>
<p>Обратите внимание на тот факт, что конвертация в тип, понятный SQL-серверу произойдет автоматически. Однако следует иметь в виду, что при определенных условиях подобной автоматизм может вызвать некоторые проблемы.</p>
<p>Например, для MS SQL сервера переменные памяти с дробной частью будут сконвертировны в тип REAL, что может привести к потере точности. Вместо точного значения 1.1 сервер интерпретирует это значение, как приближенное 1.0999999. В большинстве случаев - ничего страшного. Однако иногда это может иметь принципиальное значение.</p>
<p>Поэтому, если Вам необходимо передать данные "как есть", то придется самостоятельно формировать символьную строку.</p>
<pre class="bbcode">  
  LOCAL lnPar1, lcPar2, lcStringSQL  
  lnPar1 = 123.456  
  lcPar2 = "Новое значение"  
  lcStringSQL = "{Call MyProc ("+TRANSFORM(m.lnPar1)+",'"+m.lcPar2+"')}"  
  SQLExec(lnHandle,m.lcStringSQL)</pre>
<p><b>Замечание</b></p>
<p>Если Вы формируете символьную строку самостоятельно, то предварительно уточните как именно записываются константы разных типов в синтаксисе того или иного сервера.</p>
<p>Например, для MS SQL сервера символьная константа, по умолчанию, обрамляется одинарными кавычками. Двойными кавычками обрамляются имена объектов. Поэтому символьная константа обрамленная двойными кавычками может вызвать сообщение о синтаксической ошибке.</p>
<p>Константа типа Date или DateTime также может записываться разными способами. Хотя, универсальный формат, который понимают большинство серверов - это символьная строка вида 'ГГГГММДД'. Т.е. дата 6 января 2010 года должна быть записана как '20100106'</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-peredat-parametry-v-hranimuyu-proczeduru-servera/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с удаленными данными или SQL-серверами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-vyzvat-hranimuyu-proczeduru-servera/</link>
					<title><![CDATA[Как вызвать хранимую процедуру сервера]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 10:24:26 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как вызвать хранимую процедуру сервера</h1>
													</header>
													<p><b>Вопрос</b></p>
<blockquote><p>Как вызвать хранимую процедуру сервера?</p></blockquote>
<p><b>Ответ</b></p>
<p>В FoxPro для этой цели можно использовать функцию SQLExec(). Стандартный синтаксис для вызова хранимой процедуры любого сервера является команда <b>Call</b>, обрамленная фигурными скобками. Примерно так:</p>
<pre class="bbcode">SQLExec(m.lnHandle,"{Call MyProc (par1, par2)}")</pre>
<p>Для MS SQL сервера можно использовать "локальный", т.е. пригодный только для сервера MS SQL способ вызова:</p>
<pre class="bbcode">SQLExec(m.lnHandle,"EXECUTE MyProc par1, par2")</pre>
<p>В данных примерах использовано следующее обозначение:</p>
<p>m.lnHandle - это число, являющееся номером ранее установленного соединения с сервером.<br />
MyProc - имя запускаемой процедуры<br />
par1, par2 - параметры, передаваемые в процедуру</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-vyzvat-hranimuyu-proczeduru-servera/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с удаленными данными или SQL-серверами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-podavit-vydachu-sistemnogo-okna-nastrojki-soedineniya-v-sluchae-oshibki/</link>
					<title><![CDATA[Как подавить выдачу системного окна настройки соединения в случае ошибки]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 10:22:37 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как подавить выдачу системного окна настройки соединения в случае ошибки</h1>
													</header>
													<blockquote><p><b>Вопрос</b></p>
<p>Я настриваю соединение программно через команду SQLConnect() или команду SQLStringConnect(). В случае ошибки создания соединения возникает системное окно для настройки реквизитов соединения. Как можно подавить выдачу этого окна, просто выдав пользователю сообщение об ошибке?</p>
<p><b>Ответ</b></p>
<p>Если Вы используете для создания соединения объект <b>Connection</b> базы данных, то откройте этот объект на редактирование и сделайте следующие настройки:</p></blockquote>
<ol>
<li>В разделе "Display ODBC login prompts" установите переключатель в положение "Never"</li>
<li>Убедитесь, что в разделе "Data Procesing" переключатель "Display Warnings" выключен</li>
</ol>
<p>Если Вы настраиваете соединение исключительно программными средствами, то установить нужные значения этих настроек можно, используя функцию SQLSetProp(). Это настройки <b>DispLogin </b>и <b>DispWarnings</b>.</p>
<p>Однако, как видно из синтаксиса функции SQLSetProp(), она делает настройки для конкретного соединения. Первым параметром идет номер уже созданного соединения. Но ведь соединения еще нет. Его только собираются создать.</p>
<p>Чтобы преодолеть это противоречие, используют соединение с номером 0. Физически - это вообще не соединение. По сути, это будут настройки для любого <u>нового</u> соединения, поскольку номером 0 обозначают первое не занятое значение номера соединения. На уже созданные соединения эти настройки не распространяются.</p>
<p>Получается примерно такой код:</p>
<pre class="bbcode">  
 * Сохранение текущих значений настроек  
  LOCAL llDispWarning, lnDispLogin  
  llDispWarning=SQLGetProp(0,'DispWarning')  
  lnDispLogin=SQLGetProp(0,'DispLogin')  
    
 * Установка этих настроек в значения, препятствующие выдаче системных сообщений  
  SQLSetProp(0,'DispWarning',.F.)  
  SQLSetProp(0,'DispLogin',3)  
    
 * Формируем строку соединения для MS SQL сервера  
  LOCAL lcStringConnect  
  lcStringConnect='DRIVER=SQL Server;'+;  
  		'SERVER=Имя_Сервера;'+;  
  		'UID=Логин_Пользователя;'+;  
  		'PWD=Пароль_Пользователя;'+;  
  		'DataBase=Имя_базы_данных'  
    
 * Собственно попытка создания соединения  
  lnNewConnection = SQLStringConnect(m.lcStringConnect)  
  IF m.lnNewConnection &lt;= 0  
 	* Произошла ошибка в момент установки соединения. Выясняем причину  
  	LOCAL laError(1)  
  	=AERROR(laError)  
 	* Анализ массива laError для уточнения причины ошибки  
  ELSE  
 	* Соединение успешно установлено   
 	* и его номер записан в переменную lnNewConnection  
  ENDIF  
    
 * Восстановление исходных настроек  
  SQLSetProp(0,'DispWarning',m.llDispWarning)  
  SQLSetProp(0,'DispLogin',m.lnDispLogin)</pre>
<p>В принципе, значение настройки DispWarning и так по умолчанию равно .F. Здесь это делается на всякий случай</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-podavit-vydachu-sistemnogo-okna-nastrojki-soedineniya-v-sluchae-oshibki/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с удаленными данными или SQL-серверами]]></category>				</item>
											<item turbo="true">
					<link>https://foxclub.ru/faqs/kak-opredelit-prichinu-oshibki/</link>
					<title><![CDATA[Как определить причину ошибки]]></title>
                    					    <author><![CDATA[Владимир Максимов]]></author>
                    										    <pubDate>Wed, 26 Aug 2020 10:19:10 +0000</pubDate>
										<turbo:content>
						<![CDATA[
						<header>
														<h1>Как определить причину ошибки</h1>
													</header>
													<p><b>Вопрос</b></p>
<blockquote><p>Выполнение операции с SQL-сервером завершилось неудачей. Как определить факт того, что произошла ошибка, и какая именно ошибка произошла?</p></blockquote>
<p><b>Ответ</b></p>
<p>Тот факт, что операция на сервере закончилась неудачей, определяется в зависимости от используемого способа обращения к серверу.</p>
<p>Если обращение идет через функции SQLExec(), то сама эта функция возвращает значение меньше нуля в случае ошибки.</p>
<p>Если обращение идет через RemoteView или Cursor Adapter, то операция сброса изменений на сервер осуществляется функцией TableUpdate(). В случае неудачи (ошибки) эта функция вернет .F.</p>
<p>Для определения причины возникновения ошибки предназначена функция AERROR(). Использовать можно следующим образом:</p>
<pre class="bbcode">  
 * При работе через SQLExec()  
  IF SQLExec(...)&lt;0  
  	LOCAL laError(1)  
  	=AERROR(laError)  
 	* Анализ массива laError для уточнения причины ошибки  
  ENDIF  
    
 * При работе через Remote View или Cursor Adapter  
  IF TableUpdate(.T.,.T.,"MyView")=.F.  
  	LOCAL laError(1)  
  	=AERROR(laError)  
 	* Анализ массива laError для уточнения причины ошибки  
  ENDIF</pre>
<p>При работе с удаленными данными первый элемент полученного массива всегда будет иметь значение 1526 - ошибка ODBC-соединения.</p>
<p>Остальные элементы массива будут содержать информацию об ошибке самого сервера. Т.е., какая именно ошибка произошла на сервере.</p>
<div id=block_author-rcl><h3>Автор публикации</h3><div class="rcl-userlist"><div class="userlist rows-list"><div class="user-single" data-user-id="4899">
    <div class="userlist_top">
		<div class="status_author_mess offline">не в сети 26 лет</div>        <h3 class="user-name">
            <a href="https://foxclub.ru/account/?user=4899">Владимир Максимов</a>
        </h3>
    </div>

    <div class="userlist_cntr">
        <div class="thumb-user">
            <a title="Владимир Максимов" href="https://foxclub.ru/account/?user=4899">
				<img alt='' src='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=70&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/1c0f189997f17b35ef1beca43d0e27d0?s=140&#038;d=mm&#038;r=g 2x' class='avatar avatar-70 photo' height='70' width='70' />            </a>
			        </div>

        <div class="user-content-rcl">
			<i class="rcli fa-comment"></i>Комментарии: 0<i class="rcli fa-file-text-o"></i>Публикации: 65<i class="rcli fa-calendar-check-o"></i>Регистрация: 02-09-2000        </div>
    </div>
</div></div></div></div><p><a href="https://foxclub.ru/faqs/kak-opredelit-prichinu-oshibki/?utm_source=turbo" target="_blank">(далее&hellip;)</a></p>																		]]>
					</turbo:content>
					<category><![CDATA[Работа с удаленными данными или SQL-серверами]]></category>				</item>
								</channel>
</rss>
