Рассылка статей | Программирование и готовые решения
Leadersoft.ru

Рассылка статей

Программирование и готовые решения

В этом разделе сайта дается информация от https://leadersoft.ru о статьях по программированию, ответах на вопросы и др. Статьи рассылаются подписчикам и публикуются на разных сервисах. Возможно некоторая информация устарела и ссылки не работают, но эти сведения могут быть полезны, если Вы серьезно занимаетесь разработкой баз данных

Выпуск 40. Графический интерфейс

  Введение
   В этом выпуске рассказывается о графическом интерфейсе для баз данных. Несколько примеров помогут Вам грамотно оформить интерфейс. После изучения, Вы сможете изменить фон окна приложения Access, узнать код любой иконки офисного приложения, построить панель управления, используя собственные рисунки, и изменить иконку формы. Автор: Малютин Николай

Вопрос 2528:  Серый фон окна  Access
Тема:      HI. Хочу поблагодарить за учебный материал на сайте Leadersoft.ru , он помог мне в написании дипломного проекта. Хотелось бы получить ответ: Как можно изменить серый фон окна Access в программе?
Ответ. Малютин Николай
  На форуме вновь возникли вопросы по картинкам в Access. Думаю, что приведенный пример поможет решить многие такие вопросы. Одно из самых частых претензий к Access - это претензии к интерфейсу, точнее к внешнему виду. Желание "разукрасить" приложение часто решается за счет того, что главное окно Access скрывается. При этом теряется возможность использовать свои строку меню и панели инструментов - для этого делают различные имитации ToolBar. В общем решение одной проблемы порождает кучу других.Между тем Access использует весьма мощное средство - VBA, немного уступающий "классическому" VB

Итак, с самого начала.

При запуске базы данных появляется заставка Access. Между тем, достаточно в каталог с базой поместить собственный рисунок с именем ИмяБазыДанных.bmp. и тогда при старте будет сначала появляться Ваш рисунок. Или больше - поместить "нулевой" рисунок. Создать такой рисунок очень просто:

 

Public Sub NullBMP(AppFullName As String)
Dim strName As String
Dim bytPic(65) As Byte
Dim i As Long
    strName = Left(AppFullName, Len(AppFullName) - 3)
    strName = strName & "bmp"
    If Len(Dir(strName)) = 0 Then
        bytPic(0) = &H42: bytPic(1) = &H4D: bytPic(14) = &H28
        i = FreeFile()
        Open strName For Binary As #i
        Put #i, , bytPic()
        Close #i
    End If
End Sub
'пример не требует комментариев

 
Следующая претензия - серое окно.

Между тем это серое окно - обычное окно windows, и также как и другие окна принимает и обрабатывает системные сообщения, в том числе и WM_PAINT, по получении которого окно подновляет свой вид. Если перехватить сообщение WM_PAINT, посланное "серому" окну, что в это время можно нарисовать свою картинку - и она будет "как родная". Самый большой подводный камень при реализации  - то, что VBA работает медленнее, чем программа *.exe, а поток сообщений к окну весьма велик. Если попытаться запустить приведенный пример в "пошаговом" режиме, то дождаться каких либо изменений будет очень проблематично. Более того, если перед запуском Вы работали в редакторе VBA, то работа примера очень сильно замедляется (очень сильно) Поэтому данный метод лучше всего использовать, когда код перерисовки окна расположен в файле *.mde. Кроме того замечено, что в среде Win98 - Access2000 программа не всегда работает устойчиво (связано с проблемами Win98)

Перейдем к кнопкам меню и панелей инструментов.

Хотя кнопки и позволяют использовать рисунки, но только встроенные, посредством указания номера рисунка (FaceId). Учитывая, что в Office существует НЕ ОДНА ТЫСЯЧА рисунков, конечно можно подобрать нужный, но при таком количестве это весьма затруднительно (да и далеко не все отображаются самим Access) . Для этого можно использовать проводник по рисункам: 
Создаем временную панель инструментов и располагаем на ней 100 кнопок + 2 для навигации. Каждой кнопке присваиваем FaceId=1...100, 101...200, и т.д. Теперь выбрать нужный рисунок гораздо легче. Но если все же хочется именно свои рисунки, то здесь можно использовать возможность вставки рисунка на кнопку из буфера обмена. Задача - поместить в буфер обмена собственный рисунок. Рисунки можно хранить в таблице базы в двоичном виде, либо использовать прямо с диска. В примере рисунки через временный файл загружаются в ImageList, откуда и используются по необходимости.

Формы- у всех форм одинаковые иконки.

Ну, после всего, что уже сделали, это особого труда не составит. Возьмем иконку (ImageList или файл) и, используя средства системы, присвоим эту иконку нужному окну.

Пример можно загрузить по ссылке: 

Код 2889:  Предложение сотрудничества
 Имеется рабочая база в Access 97 .mde нужно создать аналогичную mdb.
т. 937-5523 ext.119
Unistaff Personnel Services
Александр.

Выпуск 39. Восстановление почты Outlook Express

  Введение
   В этом выпуске рассылки рассказывается о том, как используя Microsoft Access, можно восстановить почту Outlook Express. А также ...
   Поздравляю всех с наступающим Новым годом!  Желаю всем в наступающем году процветания, больших творческих успехов, благополучия, удачи во всех начинаниях. Здоровья, и счастья Вам и Вашим близким в Новом году!

Вопрос 2528:  Помогите восстановить почту?
Тема:      Я пользуюсь почтовой программой Outlook Express, в результате "сбоя" компьютера перестала открываться почтовая программа. Запускаю ее, и компьютер зависает на долгое время. Приходиться через Ctl+Alt+Del "убивать" процесс.
Ответ. Самый простой совет - это надо архивировать почту, но это не решение проблемы. С каждым может такое случиться, вот и я попытаюсь коротко объяснить, как можно "заставить" работать почтовую программу. Пример привожу из личной практики. Предполагаю, что у Вас на компьютере установлен Microsoft Office, включая Access, Outlook, и Outlook Express.
  1.  До этого почту пытались восстановить разными методами. Например, путем  экспорта и импорта писем в Outlook и Outlook Express. Путем замены версий 5 версии Outlook Express на 6. Путем поиска специальных программ в интернете по этой тематике, но часть из них работает по принципу: сначала  сделай архив, а только потом ее восстанавливай. Другие  работают правильно, т.е. пытаются анализировать dbх файл. Но в этом случае Вы должны точно знать, что надо восстанавливать, да и программы стоят несколько сот долларов. Реально же в базе данных было около 300 файлов, объем почты - 250МБ, и сразу найти испорченные данные было невозможно.
  2. Решение как всегда оказалось достаточно простое, но сначала немного о почтовых базах данных. Принцип хранения данных Outlook и Outlook Express сильно отличается. В первой программе почта сохраняется в одном файле *.pst, в другой  - в файлах *.dbx. Например, Вы создаете папку  test, одновременно открывается файл test.dbx. Переименовываете папку test в test1, также изменяется и имя файла в test1.dbx. За это и пришлось "зацепиться",  написав маленькую программу. А теперь поговорим и о самом восстановлении.
  3. Средствами поиска Windows (кнопка "Пуск" - "Найти" - "Файлы и Папки" ...) находите папки, где есть файлы базы данных Outlook (например, D:\Documents and Settings\Антон\Local Settings\Application Data\Microsoft\Outlook) и Outlook Express (например, D:\Documents and Settings\Антон\Local Settings\Application Data\Identities\{...}\Корпорация Майкрософт\Outlook Express). Пример, для Windows 2000.
  4. Переименовываете папку Outlook Express, например, Outlook Express1, а у Outlook достаточно переименовать файл: outlook.pst, например, в outlook1.pst. Запускаете поочередно программы Outlook Express и Outlook. Минимальное количество файлов для работы программ, будет создано автоматически (или после небольших ваших ответов на вопросы программы Outlook).
  5. Теперь Вам необходимо проанализировать информацию в папках Outlook Express и Outlook Express1. Попробуйте создать в Outlook Express папку test. Теперь скопируйте любой dbx файл из Outllook Express1 в файл test.dbx. Открыв почту, вы увидите, что папка test изменилась, в ней появились письма. Осталось только автоматизировать этот процесс.
  6. Создавать напрямую, в Outlook Express через VBA, не получиться (или у меня нет такой информации). Но их достаточно легко создать в Outlook. Смотрите пример ниже, или скачайте программу: la_automat.mdb (5 пример)
   7. На заключительном этапе Вам остается импортировать папки в Outllook Express из Outllook, далее через проводник WIndows cкопируйте из нерабочего архива Express dbx файлы. Что не надо копировать? Например, folders.dbx (от нее зависает Express), а также основные папки Удаленные, Отправленные. Их может и не быть в каталоге, т.к. возможно они были переименованы в результате сбоя компьютера, но почту вы прочтете в папке с другим именем.
   8. Когда Вы откроете Express, папки будут с разными экзотическими именами, например, "  (1)", "    ". Но это не так важно. Корреспонденция сохраняется полностью. Остается в ручную сгруппировать письма и потом сжать базу. Если Вы не знаете, что за письма лежат в папке, то лучше их удалить. Иногда полезно вовремя избавиться от ненужной информации.  Мусора всегда хватает.
VBA пример:  Создание папок в Outlook
 '==============================================================
' Кнопка по которой запускается программа
Private Sub butExecute_Click()
Dim app As Outlook.Application 'Приложение программы
Dim i As Integer 'Счетчик
Dim myNamespace, myfolder As MAPIFolder, mynewfolder

On Error GoTo 999
Set app = New Outlook.Application
Set myNamespace = app.GetNamespace("MAPI")
Set myfolder = myNamespace.GetDefaultFolder(olFolderInbox)
With Application.FileSearch
.NewSearch
.LookIn = Me.myFolderInternetExpress ' = c:\
.FileName = "*.dbx" ' Выбираем файлы для Outlook Express
.SearchSubFolders = True
If .Execute(SortBy:=msoSortByFileName, _
SortOrder:=msoSortOrderAscending) > 0 Then
Dim strFile As String
For i = 1 To .FoundFiles.Count
strFile = fGetFileName(.FoundFiles(i))
Set mynewfolder = myfolder.Folders.Add(strFile)
DoEvents
Next i
End If
End With

app.Quit 'Закрываем Outlook
MsgBox "Папки созданы!", vbExclamation, "Почта"
Exit Sub
999:
MsgBox Err.Description 'Ошибка
Err.Clear
Resume Next
End Sub

' Получение имени файла для создания папки
Public Function fGetFileName(strPath As String) As String
Dim fs
On Error GoTo 999
Set fs = CreateObject("Scripting.FileSystemObject")
fGetFileName = fs.GetBaseName(strPath)
Set fs = Nothing

Exit Function
999:
MsgBox Err.Description, vbCritical, strPath
Err.Clear
End Function

Выпуск 37. Применение ListView

  Новости
    31.03.2002. Добавлены примеры в файлы la_report1.mdb и la_activex1.mdb. Описание этих примеров дано в этом выпуске ниже.
    30.03.2002. Вышла рассылка для специалистов "Профессионально об Access". В этой подписке дается описание класса, который может быть применяться при разработке справочников Access, например, для учета клиентов, работников, товаров и т.п.

Вопрос:  Расскажите, пожалуйста, зачем нужен элемент ListView
Ответ. ListView - этот элемент имитирует рабочую область стола Windows. Таким образом, с помощью него Вы можете создать в форме базы данных область, с иконками которые можно будет передвигать или при двойном нажатии вызывать нужную программу или объект базы данных.
   Данный элемент не встроен в Access, поэтому, прежде чем его использовать надо сделать ссылку на библиотеку mscomctl.ocx через редактор VBA. Также с этим объектом используется другой элемент ImageList. Он необходим для сохранения иконок. Настройку и связь этих элементов в форме лучше использовать через конструктор, т.е. дважды нажмите на элемент и перед Вами отобразиться окно с группой вкладок и настройками. Пример использования этих элементов дан ниже.

' la_activex1.mdb (Пример 11) ===========================================
' Данный код необходимо добавить в форму
Public myNewList As MicrosoftList
Private Sub Form_Load()
If myNewList Is Nothing Then
Set myNewList = New MicrosoftList
Set myNewList.Tree = Me.myList.Object
' Загружаем узлы дерева из запроса
myNewList.Load "sqlListView"
End If
End Sub
' MicrosoftList =======================================================
' Объявляем класс ListView из Mscomctl.ocx
Public WithEvents Tree As MSComctlLib.ListView

' События при нажатии на иконку
Private Sub Tree_DblClick()
MsgBox Me.Tree.SelectedItem.Text, vbInformation, "Двойное нажатие"
End Sub

' Загрузка элемента данными из запроса
Public Function Load(strSQL As String) As Boolean
Dim myKey As String, idx As Long
Dim rst As ADODB.Recordset
On Error GoTo 999

' Загрузка дерева
Set rst = New ADODB.Recordset
rst.Open strSQL, Application.CurrentProject.Connection
Me.Tree.ListItems.Clear
idx = 1
Do Until rst.EOF
' Создание узла и его ключей
myKey = "la_" & rst!Тип
Me.Tree.ListItems.Add idx, myKey, Nz(rst!Наименование), "PC", "PC"
rst.MoveNext
idx = idx + 1
Loop
Load = True

998:
rst.Close
Set rst = Nothing
Err.Clear
Exit Function
999:
Load = False
MsgBox Err.Description
On Error Resume Next
Resume 998
End Function
Вопрос:  1832
Тема:      Отчеты
Пример:  la_report1.mdb (№20)
Сообщение: Есть одна проблема. Это организация вывода на печать. Дело в том что мне необходимо распечатывать из всей таблицы только одну запись, которая активна в форме (кстати как сгенерировать отчет только по этой одной записи а не по всей таблице).
Ответ.     Самое простое - это на этапе открытия отчета изменить источник записей, т.е sql запрос. Для ссылки на объект формы используйте объект Forms, например, "Select * From [Справочник] WHERE Цена = " & [Forms]![frmСправочник]![Цена]. Пример:

Private Sub Report_Open(Cancel As Integer)
Me.RecordSource = "SELECT * From Cправочник WHERE [Цена]<50"
End Sub

Вопрос:  1858
Тема:      Отчеты
Пример:  la_report1.mdb (№19)
Сообщение: Форматируется отчет (расчетная ведомость) по сотрудникам предприятия. Столбцы отчета представляют собой наименования кодов начислений и удержаний в текущем месяце, количество которых подсчитывается на этапе открытия отчета. Подскажите, как можно вообще можно изменить размер отчета во время исполнения программы.
Ответ. Вариантов может быть несколько. Один из способов это создать несколько подчиненных отчетов и при необходимости менять источник данных при открытии основного отчета. Например,
Private Sub Report_Open(Cancel As Integer)
If MsgBox("Изменить поля отчета?", vbInformation + vbOKCancel) = vbOK Then
Me.subReport.SourceObject = "Отчет.Пример 19_sub2"
End If
End Sub
Вопрос:  1880
Тема:      Отчеты
Пример:  la_report1.mdb (№20)
Сообщение: Как вывести в отчете сумму на каждом листе? У меня в отчете несколько листов. Приходится общую сумму листа считать вручную. Общую сумму отчета делать умею, но вот каждого листа в отдельности нет.
Ответ. Николай Малютин Если "превлечь" немного программирования, то это можно решить так:
1. В нижнем колонтитуле отчета (там, где выводятся номер страницы) создаем поле для отображения суммы.(назовем P1)
2. В свойствах раздела "НижнийКолонтитул" назначаем процедуру на событие "Форматирование"
3. Аналогично процедуру "форматирование" для ОбластиДанных
4. И пишем несколько строк программы

Option Compare Database
Dim sSum
Private Sub НижнийКолонтитул_Format(Cancel As Integer, FormatCount As Integer)
Me.P1.Value = sSum
sSum = 0
End Sub

Private Sub ОбластьДанных_Format(Cancel As Integer, FormatCount As Integer)
sSum = Me.V1.Value + sSum
End Sub
Виктор Конюков: Идея интересная и очень нужная, особенно при формировании бухотчетности. Но потребуется дополнение к программе, т.к. при форматировании с отчетом из нескольких страниц к сумме каждый раз будет добавляться первая строка таблицы следующей страницы.
Вопрос:  1928
Тема:      Запросы
Сообщение: При использовании запроса на добавление в таблицу при случайном нажатии происходит добавление несколько раз одного блока, т.е. дублирование добавления. Как этого можно избежать?
Ответ. Один из вариантов заключается в том, что в событии Click, после выполнения запроса, добавляется цикл в котором происходит временное отключение кнопки.
Private Sub Кнопка0_Click()
Dim i As Long
' DoCmd.RunSQL "..."
Me.Кнопка1.SetFocus ' Меняем фокус
For i = 0 To 5000
Me.Кнопка0.Enabled = False
Next
Me.Кнопка0.Enabled = True
End Sub

Выпуск 38. Автозагрузка файлов в базу данных

  Новости
    31.03.2002. Добавлены примеры в файлы la_files.mdb. Этот пример будет полезен для чтения имен файлов и загрузки их содержимого в таблицу, например, при обработке писем. При получении писем по email Вам достаточно их скопировать в папку в с программой. После запуска формы автоматически файлы и их содержимое будет загружаться в таблицу.

Вопрос:  2164
Тема:      Файловая система
Пример:  la_files.mdb (Номер 5)
Сообщение: Я задался идей создать базу данных моей музыкальной коллекции, размещённой на жёстком диске. Пытаюсь это сделать с помощью Access. Но вот одна трудность - мне нужно, чтобы автоматически обновлялись данные в определённой таблице(цах). А данные эти - названия исполнителей и названия песен, записанные в виде ID тэгов в музыкальных файлах MP3. Т.е. при помещении в определённую папку новых MP3 файлов их названия должны автоматически пополнять базу данных. Может вы подскажете каким образом и с помощью чего я смогу это сделать. В литературе я не нашёл относящихся к этому материалов. С программированием почти не знаком.
Ответ. Хотя этот вопрос впервые встречается среди многих других вопросов по Access, но можно сказать, что эта тема эта достаточно важна не только для новичков, но и для тех, кто профессионально занимается базами данных.
    Например, представим что у Вас есть электронный магазин и все заказы приходят к Вам в виде писем по электронной почте. Ручная обработка писем, их сортировка, чтение и ввод данных в базу данных может занять значительное время. При этом будет трудно избежать ошибок при вводе информации, если вдобавок вы не имеете профессиональных операторов. Естественно можно придумать так, что все письма будут сохраняться в определенной папке, после того, как Вы открываете базу данных, программа автоматически будет читать имена файлов, проверять наличие их (по названию, по дате и времени их создания)  и далее загружать выборочно текст в таблицу базы данных (текст может быть разбит тегами на разделы).
   Попробуем автоматизировать этот процесс. Ниже дается описание алгоритма, что нужно сделать, после этого идет код на VBA.
   1 этап. Создаем макрос AutoExec. Назначение этого макроса - это автоматический запуск некоторой программы, которая должна выполняться всегда при открытии базы. Название программы - funAutoReadAllFiles(). На вход программы необходимо передать данные по каталогу, где надо искать файлы и расширение файлов, которые необходимо считать.
   2 этап. Создаем подпрограмму по загрузке файлов  funAutoReadOneFile. Цель ее - проверка содержимого файла в базе данных и если файла нет, то загрузить его. На вход программы подается информация об имени файла и таблицы, куда необходимо загрузить данные.
   Данный код взят из файла la_files.mdb
'==============================================================
' Прочитаем имена файлов и загрузим их в таблицу
'
Private Sub funAutoReadAllFiles(strDir As String, strFileExt As String)
Dim i As Long, rst As DAO.Recordset
On Error GoTo 999
With Application.FileSearch
.NewSearch
.LookIn = strDir ' *.name
.FileName = strFileExt ' *.txt
.SearchSubFolders = False
If .Execute(SortBy:=msoSortByFileName, _
SortOrder:=msoSortOrderAscending) > 0 Then
For i = 1 To .FoundFiles.Count
If MsgBox("Загрузить файл: " & .FoundFiles(i), vbInformation + vbOKCancel, "Загрузить") = vbOK Then
funAutoReadOneFile .FoundFiles(i), "Таблица5"
Me.table5.Requery
End If
Next i
End If
End With
Exit Sub 'Выходим из программы
999:
MsgBox Err.Description
Err.Clear 'Очищаем поток от ошибок
End Sub

'==============================================================
' Загружаем файл в таблицу
'
Private Function funAutoReadOneFile(strFileName As String, strTable)
Dim fs, f, flag
Dim dbs As DAO.Database, rst As DAO.Recordset

On Error GoTo 999
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.GetFile(strFileName)

' Проверка файла
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("select * from " & strTable)

If rst.RecordCount Then
rst.MoveLast
rst.MoveFirst
End If

rst.FindFirst "[FileName] = '" & strFileName & "'"
If rst.NoMatch = False Then
dbs.Close
rst.Close
Exit Function
End If

' Добавление информации о дате создания
rst.AddNew
rst!FileName = strFileName
rst!DateCreated = f.DateCreated

' Добавление информации о содержимом
rst!Memo = ""
Set f = fs.OpenTextFile(strFileName, 1, False)
Do While f.AtEndOfStream <> True
rst!Memo = rst!Memo & f.ReadLine ' Читаем построчно
Loop
f.Close

' Сохранение содержимого
rst.Update
rst.Close
dbs.Close

Exit Function
999:
MsgBox Err.Description
Err.Clear
rst.Close
End Function

Private Sub butCode1_Click()
Stop
End Sub
Вопрос:  2168
Тема:      Программирование
Сообщение: А почему в ваших примерах встречается переход по ошибке On Error Goto 999, а не On Error Goto Ошибка. Так, например, будет более понятно.
Ответ.      Возможно да, но у меня есть несколько причин, например,
1. При переходе по ошибке, компилятор проводит сравнивание. Когда сравниваются несколько строк, то при их сравнении имеет значение каждая буква. При этом, если буквы еще находятся в верхней части таблицы символов, то сравнение будет чуточку быстрее. '9' выше буквы 'О'
2. 999 - это число магическое, т.е. ранее при разработке программ не рекомендуется делать программный код для 1 функции более 1000 строк. Следовательно 999 - это предел записей, т.е. число само по себе говорит об ошибке.
3. В третьих, легче и быстрее написать 999, чем 'Ошибка'.

Выпуск 36. Структура и чтение DBF файлов

  Новости
    29.03.2002. Вышла рассылка для специалистов "Профессионально об Access". Разосланы подписчикам образцы договора на разработку базы данных и техническое задание с примерами интерфейса.
    19.03.2002. Добавилась визитка профессионального разработчика баз данных Microsoft Access: Kapitulsky Alexander.

Статья:  Структура и чтение DBF файлов
Пример: 
la_convert.mdb
   DBF файл (dbase) один из самых популярных форматов баз данных. Связано это с тем, что он самый "древний" из баз данных. Первые его версии появились аж в 1983 году. Конечно, за такой длительный срок существования было разработано много разных баз данных, и  постоянно встречаются dbf файлы из которых необходимо "вытащить" информацию.
    Форматы файлов разделяются на версии  II, III, IV и т.п. При этом надо отметить, что "значительных" отличий от версии к версии нет. Таким образом, достаточно изучить методы чтения одного типа файлов и уже далее легко можно доработать программу под другие форматы.
    Зачем это нужно. Иногда, работая с базой данных после присоединения таблиц, драйвер возвращает неправильные текстовые данные (нарушена кодировка символов). Возможен вариант, когда Вам необходимо считать memo поля, а Access не позволяет это сделать. Поэтому, чтобы себя свободно чувствовать в этой области, надо изучить и загрузку данных без dbf драйверов.
    Вся статья разбита на 3 части, где сначала идет описание dbf файла IV версии, а далее описание dbf функций, а потом их применение в VBA.
Структура файла. 
    Каждый файл состоит из трех частей: заголовка, описания записей и собственно данных. Ниже представлено короткое описание каждого из разделов.
I. Описание заголовка
Смещение Длина в байтах Содержание
0 1 Номер версии dBase 
    Биты 0-2 - dBase версия (03H для версий III и IV)
Бит 3 - индикатор полей памяти
Биты 4-6 - зарезервированы для SQL
Бит 7 - Признак наличия DBT файлов dbase III+
1 3 Дата последнего изменения (в формате ГГММДД)
4 4 Количество записей в базе данных
8 2 Длина заголовочной записи в байтах
10 2 Длина записи данных в байтах
12 2  Резервные
14 1  Признак пересылок
15 1  Признак кодирования ( 1-данные закодированы)
16 12  Зарезервированы для сетевой версии
28 1  Признак наличия/отсутствия мультииндексных файлов 01Н - имеется MDX файл, 00H - отсутствует MDX файл
29 3  Резервные
32 32*N  Описание N полей записи данных (по 32 байта на каждое поле)
32+32*N+1 1  Признак конца заголовочной записи (0DH)
 
   
II. Описание полей в Dbase IV (Всего не более 255 полей)
Смещение Длина в байтах Содержание
0 11  Имя поля в ASCII - кодах. Пустые места = 00H
11 1  Тип поля в ASCII - кодах (С, N, F, L, D, M)
C - символьный (ASCII символы)
N - 1 числовой (0...9)
F - 2 числовой (0...9)
L - Логический (YyNnTtFf)
D - Дата (ГГММДД)
M - заметки, номер блока DBT файла
12 4  Адрес поля в памяти (для внутреннего использования dbase)
16 1  Длина поля в байтах (не более 255 символов)
17 1  Количество знаков после десятичной точки в байтах для числовых полей, иначе 0
18 2  Зарезервировано для многопользовательских систем 
20 1  Идентификатор рабочей области
21 2  Зарезервировано для многопользовательских систем
23 1  Используется программой SET FIELDS
24 8  Зарезервировано
 
 
III. Данные в базе данных
Смещение Длина в байтах Содержание
0 1  Байт, содержащий отметку об удалении записи. Если запись удалена он равен *, иначе " " (blank)
1 Сумма длин полей  Запись хранится в виде строки ASCII символов без разделяющих знаков
 1AH - конец действительной области данных

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

 

Функции чтения DBF файла
    Данный пример взят из файла la_convert.mdb. Сохраните код в любом текстовом файле, а потом импортируйте его в свой модуль из редактора VBA.
' Start-->
Attribute VB_Name = "basDbfConverter"
Option Compare Database
Option Explicit
'***************************************************************
' Подписка: "Access 2000 - программирование и готовые решения"
' Тема: Работа с внешним dbf файлом версии III или IV
' Версия: 1 от 26.03.2002
' Автор: Copyright © LeaderAccess, LTD
' Сайт: http://www.leadersoft.ru
' Примечание: Ссылка на автора и программу обязательна!
'

Const alfaWin As String = "абвгдеёжзийклмнопрстуфхцчшщьэъюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЭЪЮЯ№ыЫ"
Const alfaDos As String = " ЎўЈ¤Ґс¦§Ё©Є«¬­®ЇабвгдежзиймнкопЂЃ‚ѓ„…р†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—™њќљћџьл›"

' Заголовок, прочитанный в буфер
Public Type dbfBufHeader
buf As String * 4 ' Номер версии и дата
RecordCount As Long ' Число записей
HeaderLength As Integer ' Длина заголовка
RecordLength As Integer ' Длина записи
End Type

' Характеристика поля базы данных
Public Type dbfFields
Name As String ' Название поля
Type As String ' Тип поля
Length As Integer ' Длина поля
Dec As Integer ' Число знаков после запятой
End Type

' Данные по записи
Public Type dbfRecord
Mark As String ' 1 байт. Флаг маркировки: * - удалена или " "
Data() As String ' Данные всех полей
End Type

' Полная информация по заголовку
Public Type dbfHeader
VersionNumber As Integer ' Номер версии
LastUpdate As Date ' Дата последнего обновления
HeaderLength As Integer ' Длина заголовка
RecordCount As Long ' Число записей
RecordLength As Integer ' Длина записи
NumberFields As Integer ' Число полей
FileSize As Long ' Размер файла
PathDBF As String ' Имя файла
PathDBT As String ' Имя файла
TableAccess As String ' Таблица в Mdb файле
Fields() As dbfFields ' Данные по полям
Record As dbfRecord ' Информация по 1 записи
DBF As Integer ' Указатель на DBF файл
DBT As Integer ' Указатель на MEMO файл
End Type

'==============================================================
' Прочитать данные о заголовке dbf файла
' и сохранить данные в структуре hDbf
'

Function dbfReadHeader(hDbf As dbfHeader, strPath As String, strTableAccess As String) As Long
Dim bufHdr As dbfBufHeader ' Заголовок - буфер
hDbf.DBF = FreeFile() ' Создаем указатель
With hDbf
Open strPath For Binary As #.DBF
Get #.DBF, , bufHdr ' Читаем заголовок
.PathDBF = strPath
.TableAccess = strTableAccess
.VersionNumber = Asc(Left$(bufHdr.buf, 1)) And (7) ' Номер версии
.LastUpdate = dbfReadDate(Mid$(bufHdr.buf, 2, 3)) ' Дата
.RecordCount = bufHdr.RecordCount ' Число записей
.HeaderLength = bufHdr.HeaderLength ' Длина заголовка
.RecordLength = bufHdr.RecordLength ' Длина записи
.NumberFields = (hDbf.HeaderLength - 33) / 32 ' Число полей
.FileSize = 1 + .HeaderLength + .RecordLength * .RecordCount ' Длина файла

' Проверка версии
If .VersionNumber <> 3 Then
dbfReadHeader = -1 ' Это не DBase Файл
Exit Function
End If

' Проверка числа записей
If .RecordCount = 0 Then
dbfReadHeader = -2 ' Нет записей
Exit Function
End If

' Меняем в заголовке число полей
ReDim .Fields(.NumberFields - 1)
' Выделяем память для данных 1 записи
ReDim .Record.Data(.NumberFields - 1)
End With

' Нет ошибок
dbfReadHeader = 0
End Function

'==============================================================
' Цель. Прочитать данные из заголовка
' о полях: Имя, Тип, Длина, Дес. точка
'

Function dbfReadNameFields(hDbf As dbfHeader) As Long
Dim i As Long, buf As String, hEof As String
With hDbf
Seek #.DBF, 33 ' Устанавливаем позицию
buf = Space$(32) ' Выделяем память
For i = 0 To .NumberFields - 1
Get #.DBF, , buf ' Читаем строку длиной 32 байта
.Fields(i).Name = Trim(dbfTrimString(Left$(buf, 11), 11))
.Fields(i).Type = Mid$(buf, 12, 1)
.Fields(i).Length = Asc(Mid$(buf, 17, 1))
.Fields(i).Dec = Asc(Mid$(buf, 18, 1))
Next i
hEof = Input$(1, #.DBF) ' Конец заголовка
If Asc(hEof) <> 13 Then
dbfReadNameFields = False ' Плохой заголовок
Else
dbfReadNameFields = True ' Правильная структура
End If
End With
End Function

'==============================================================
' Сохраняем данные о полях в таблице
'

Function dbfSaveNameFields(hDbf As dbfHeader) As Long
Dim i As Long, s As String
Dim dbs As DAO.Database, tdf As DAO.TableDef

With hDbf
' Удаляем ненужную таблицу
On Error Resume Next
DoCmd.DeleteObject acTable, .TableAccess
Err.Clear

' Создаем поля
Set dbs = CurrentDb
Set tdf = dbs.CreateTableDef(.TableAccess) 'Создаем таблицу
For i = 0 To .NumberFields - 1
s = .Fields(i).Name
Select Case .Fields(i).Type
Case "C": tdf.Fields.Append tdf.CreateField(s, dbText, hDbf.Fields(i).Length)
Case "D": tdf.Fields.Append tdf.CreateField(s, dbDate)
Case "F": tdf.Fields.Append tdf.CreateField(s, dbFloat)
Case "M": tdf.Fields.Append tdf.CreateField(s, dbMemo)
Case "L": tdf.Fields.Append tdf.CreateField(s, dbBoolean)
Case "N": tdf.Fields.Append tdf.CreateField(s, dbDouble)
End Select
Next i
End With
dbs.TableDefs.Append tdf 'Добавляем таблицу
End Function

'==============================================================
' Прочитаем 1 запись в базу данных
'
Sub dbfReadRecord(hDbf As dbfHeader, NumRec As Long)
Dim buf As String, pos As Long, i As Long
Dim ss As String, p As Long

With hDbf
' Выделяем память
buf = Space$(.RecordLength)
' Находим позицию
Seek #.DBF, 1 + .HeaderLength + (NumRec - 1) * .RecordLength
' Читаем запись
Get #.DBF, , buf
' Чтение метки удаления "*" и " "
.Record.Mark = Left(buf, 1)
' Установка позиции
pos = 2
' Разбор данных
For i = 0 To .NumberFields - 1
' Выбор полей
ss = Mid(buf, pos, .Fields(i).Length)
ss = dbfTrimString(ss, CLng(.Fields(i).Length))

' Настройка некоторых полей
Select Case hDbf.Fields(i).Type
Case "D" ' dd/mm/yyyy
ss = Right$(ss, 2) + "/" + Mid$(ss, 5, 2) + "/" + Left$(ss, 4)
Case "L" ' Логическое поле T,Y или F,N
Select Case UCase$(ss)
Case "Y", "T": ss = "True"
Case "N", "F": ss = "False"
Case Else: ss = "?"
End Select
Case Else
End Select
' Назначаем данные
.Record.Data(i) = ss
' Определяем позицию следующего поля
pos = pos + .Fields(i).Length
Next i
End With
End Sub

'==============================================================
' Сохраняем данные 1 записи в таблице
'

Function dbfSaveRecord(hDbf As dbfHeader) As Long
Dim i As Long, p As Long, dbs As Database, rst As DAO.Recordset, buf As String, sn As String
On Error GoTo 999
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset(hDbf.TableAccess)
With hDbf
rst.AddNew
For i = 0 To .NumberFields - 1
buf = .Record.Data(i) ' Nz(Trim(.Record.Data(i)), " ")
sn = .Fields(i).Name
Select Case .Fields(i).Type
Case "C": rst(sn).Value = CStr(buf)
Case "D": rst(sn).Value = CDate(buf)
Case "M": rst(sn).Value = buf
Case "L": rst(sn).Value = CBool(buf)
Case "N", "F":
p = InStr(buf, ".")
If p Then buf = Left(buf, p - 1) & "," & Mid(buf, p + 1)
rst(sn).Value = CDbl(buf)
End Select
Next i
rst.Update
End With
rst.Close
Set rst = Nothing
Set dbs = Nothing
Exit Function
999:
Err.Clear
Resume Next
End Function

'==============================================================
' Программа для конвертации строки из Dos в Windows и наоборот
'

Public Function dbfReadDate(buf As String) As Date
On Error Resume Next
dbfReadDate = DateValue( _
1900 + Asc(Mid$(buf, 1, 1)) & "/" & _
Asc(Mid$(buf, 2, 1)) & "/" & _
Asc(Mid$(buf, 3, 1)))
Err.Clear
End Function

'==============================================================
' Программа для конвертации строки из Dos в Windows и наоборот
'

Public Function dbfStrConv(strData As String, buf1 As String, buf2 As String) As String
Dim i As Long, strChar As String, p As Long

' Конвертирование строки
dbfStrConv = ""
For i = 1 To Len(strData)
strChar = Mid(strData, i, 1)
p = InStr(1, buf1, strChar)
If p > 0 Then
dbfStrConv = dbfStrConv & Mid(buf2, p, 1)
Else
dbfStrConv = dbfStrConv & strChar
End If
Next
End Function

'==============================================================
' Обрезаем н��нужные данные из строки dbf
'

Public Function dbfTrimString(strData As String, lngData As Long) As String
Dim p1 As Long, p2 As Long
' Конвертируем строку из Dos в Windows
strData = dbfStrConv(strData, alfaDos, alfaWin)
' Определяем пустые данные
For p1 = 1 To lngData
If Asc(Mid(strData, p1, 1)) >= 32 Then Exit For
Next
For p2 = p1 To lngData
If Asc(Mid(strData, p2, 1)) < 32 Then Exit For
Next
dbfTrimString = Mid(strData, p1, p2 - p1)
End Function
'<--End

 

Применение DBF функций
    Выше были описаны функции для чтения dbf файла. Ниже приводится код для работы с dbase файлом. Программу можно привязать для кнопки butRead в вашей форме.
' Start-->
'==============================================================
' Читаем DBF файл и его данные

Private Sub butRead_Click()
Dim i As Long
Dim hDbf As dbfHeader ' Заголовок

' Чтение заголовка
i = dbfReadHeader(hDbf, Me.strPath, "dbfTable")
If i < 0 Then
Select Case i
Case -1: MsgBox "Неправильная версия файла", vbCritical, "Не Dbase файл"
Case -2: MsgBox "Нет записей в файле", vbCritical, "Dbase файл"
End Select
Exit Sub
End If

' Чтение/сохранение полей
If dbfReadNameFields(hDbf) = True Then
dbfSaveNameFields hDbf
Else
MsgBox "Плохой заголовок", vbCritical, "Dbase файл"
End If

' Чтение/Сохрание записи
For i = 1 To hDbf.RecordCount
dbfReadRecord hDbf, i ' Читаем запись
dbfSaveRecord hDbf ' Сохраняем прочитанную запись
Next

' Закрытие файла
If hDbf.DBF > 0 Then Close #hDbf.DBF

' Вывод информации в форме
dbfPrintHeader hDbf
End Sub
' <--End

Комментарии.
Андрей Курбацкий, mailto:Akura@ygd.gazprom.ru, mailto:A.Kurbatskii@ygd.gazprom.ru
   В формате dbf под Clipper есть одно существенное отличие. Длина строкового параметра "C" не 255 а 65535 для этого был использован не используемый для типов полей "C" 17 байт как старший байт следовательно описание полей в DBase for Clipper выглядит так
II. Описание полей в Dbase IV (Всего не более 255 полей)
Смещение   Длина в    Содержание
                     байтах
    0          11     Имя поля в ASCII - кодах. Пустые места = 00H
                         Тип поля в ASCII - кодах (С, N, F, L, D, M)
                         C - символьный (ASCII символы)
                         N - 1 числовой (0...9)
    11         1      F - 2 числовой (0...9)
                         L - Логический (YyNnTtFf)
                        D - Дата (ГГММДД)
                        M - заметки, номер блока DBT файла
    12         4      Адрес поля в памяти (для внутреннего использования  dbase)
    16         1      Длина поля в байтах (не более 255 символов, для Clipper младший байт символьных полей)
    17         1      Количество знаков после десятичной точки в байтах для
                      числовых полей, иначе 0 (Для Clipper старший байт для
символьных полей)
    18         2      Зарезервировано для многопользовательских систем
    20         1      Идентификатор рабочей области
    21         2      Зарезервировано для многопользовательских систем
    23         1      Используется программой SET FIELDS
    24         8      Зарезервировано

Следовательно с Clipper базами данных в которых были использованы C поля с длиной более 255 символов ваша программа будет работать некорректно.

 

Применение модуля для Clipper
Андрей Курбацкий,
    Я немного исправил Ваш модуль, так что он уже корректно работает с длинными
Char полями Клипперовских баз. Одно но - мне пришел исходник из рассылки и в нем строка переконвертации из DOS в WIN была разрушена. Всю строку я восстановил, но не совсем корректно, так что в высылаемом модуле она должна быть исправлена на корректную
(строка alfaDos As String)

' Start-->
'Attribute VB_Name = "basDbfConverter"
Option Compare Database
Option Explicit
'***************************************************************
' Подписка: "Access 2000 - программирование и готовые решения"
' Тема: Работа с внешним dbf файлом версии III или IV
' Версия: 1 от 26.03.2002
' Версия: 2 от 2.04.2002 (C) Курбацкий А.А.
' Автор: Copyright (C) LeaderAccess, LTD
' Сайт: http://www.leadersoft.ru
' Примечание: Ссылка на автора и программу обязательна!
'
Const alfaWin As String = "абвгдеёжзийклмнопрстуфхцчшщьэъюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЭЪЮЯыЫ"
Const alfaDos As String = " ЎўЈ¤Ґс¦§Ё©Є«¬­®ЇабвгдежзиймнкопЂЃ‚ѓ„…р†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—™њќљћџл›"
' Заголовок, прочитанный в буфер
Public Type dbfBufHeader
buf As String * 4 ' Номер версии и дата
RecordCount As Long ' Число записей
HeaderLength As Integer ' Длина заголовка
RecordLength As Integer ' Длина записи
End Type
' Характеристика поля базы данных
Public Type dbfFields
Name As String ' Название поля
Type As String ' Тип поля
Length As Integer ' Длина поля
Dec As Integer ' Число знаков после запятой
End Type
' Данные по записи
Public Type dbfRecord
Mark As String ' 1 байт. Флаг маркировки: * - удалена или " "
Data() As String ' Данные всех полей
End Type
' Полная информация по заголовку
Public Type dbfHeader
VersionNumber As Integer ' Номер версии
LastUpdate As Date ' Дата последнего обновления
HeaderLength As Integer ' Длина заголовка
RecordCount As Long ' Число записей
RecordLength As Integer ' Длина записи
NumberFields As Integer ' Число полей
FileSize As Long ' Размер файла
PathDBF As String ' Имя файла
PathDBT As String ' Имя файла
TableAccess As String ' Таблица в Mdb файле
Fields() As dbfFields ' Данные по полям
Record As dbfRecord ' Информация по 1 записи
DBF As Integer ' Указатель на DBF файл
DBT As Integer ' Указатель на MEMO файл
End Type
'==============================================================
' Прочитать данные о заголовке dbf файла
' и сохранить данные в структуре hDbf
'
Function dbfReadHeader(hDbf As dbfHeader, strPath As String, strTableAccess As String) As Long
Dim bufHdr As dbfBufHeader ' Заголовок - буфер
hDbf.DBF = FreeFile() ' Создаем указатель
With hDbf
Open strPath For Binary As #.DBF
Get #.DBF, , bufHdr ' Читаем заголовок
.PathDBF = strPath
.TableAccess = strTableAccess
.VersionNumber = Asc(Left$(bufHdr.buf, 1)) And (7) ' Номер версии
.LastUpdate = dbfReadDate(Mid$(bufHdr.buf, 2, 3)) ' Дата
.RecordCount = bufHdr.RecordCount ' Число записей
.HeaderLength = bufHdr.HeaderLength ' Длина заголовка
.RecordLength = bufHdr.RecordLength ' Длина записи
.NumberFields = (hDbf.HeaderLength - 33) / 32 ' Число полей
.FileSize = 1 + .HeaderLength + .RecordLength * .RecordCount ' Длина файла
' Проверка версии
If .VersionNumber <> 3 Then
dbfReadHeader = -1 ' Это не DBase Файл
Exit Function
End If
' Проверка числа записей
If .RecordCount = 0 Then
dbfReadHeader = -2 ' Нет записей
Exit Function
End If
' Меняем в заголовке число полей
ReDim .Fields(.NumberFields - 1)
' Выделяем память для данных 1 записи
ReDim .Record.Data(.NumberFields - 1)
End With
' Нет ошибок
dbfReadHeader = 0
End Function
'==============================================================
' Цель. Прочитать данные из заголовка
' о полях: Имя, Тип, Длина, Дес. точка
'
Function dbfReadNameFields(hDbf As dbfHeader) As Long
Dim i As Long, buf As String, hEof As String
With hDbf
Seek #.DBF, 33 ' Устанавливаем позицию
buf = Space$(32) ' Выделяем память
For i = 0 To .NumberFields - 1
Get #.DBF, , buf ' Читаем строку длиной 32 байта
.Fields(i).Name = Trim(dbfTrimString(Left$(buf, 11), 11))
.Fields(i).Type = Mid$(buf, 12, 1)
.Fields(i).Length = Asc(Mid$(buf, 17, 1))
.Fields(i).Dec = Asc(Mid$(buf, 18, 1))
Next i
hEof = Input$(1, #.DBF) ' Конец заголовка
If Asc(hEof) <> 13 Then
dbfReadNameFields = False ' Плохой заголовок
Else
dbfReadNameFields = True ' Правильная структура
End If
End With
End Function
'==============================================================
' Сохраняем данные о полях в таблице
'
Function dbfSaveNameFields(hDbf As dbfHeader) As Long
Dim i As Long, s As String
Dim dbs As DAO.Database, tdf As DAO.TableDef
With hDbf
' Удаляем ненужную таблицу
On Error Resume Next
DoCmd.DeleteObject acTable, .TableAccess
Err.Clear
' Создаем поля
Set dbs = CurrentDb
Set tdf = dbs.CreateTableDef(.TableAccess) 'Создаем таблицу
For i = 0 To .NumberFields - 1
s = .Fields(i).Name
Select Case .Fields(i).Type
'Для Clipper и длине более 256 поле представляем как М
Case "C": tdf.Fields.Append IIf(hDbf.Fields(i).Dec = 0, tdf.CreateField(s, dbText, hDbf.Fields(i).Length), tdf.CreateField(s, dbMemo))
Case "D": tdf.Fields.Append tdf.CreateField(s, dbDate)
Case "F": tdf.Fields.Append tdf.CreateField(s, dbFloat)
Case "M": tdf.Fields.Append tdf.CreateField(s, dbMemo)
Case "L": tdf.Fields.Append tdf.CreateField(s, dbBoolean)
Case "N": tdf.Fields.Append tdf.CreateField(s, dbDouble)
End Select
Next i
End With
dbs.TableDefs.Append tdf 'Добавляем таблицу
End Function
'==============================================================
' Прочитаем 1 запись в базу данных
'
Sub dbfReadRecord(hDbf As dbfHeader, NumRec As Long)
Dim buf As String, pos As Long, i As Long
Dim ss As String, p As Long
With hDbf
' Выделяем память
buf = Space$(.RecordLength)
' Находим позицию
Seek #.DBF, 1 + .HeaderLength + (NumRec - 1) * .RecordLength
' Читаем запись
Get #.DBF, , buf
' Чтение метки удаления "*" и " "
.Record.Mark = Left(buf, 1)
' Установка позиции
pos = 2
' Разбор данных
For i = 0 To .NumberFields - 1
' Выбор полей
ss = Mid(buf, pos, .Fields(i).Length)
ss = dbfTrimString(ss, CLng(.Fields(i).Length))
' Настройка некоторых полей
Select Case hDbf.Fields(i).Type
'Для Clipper и длине более 256 корректируем дляну и заново пересчитываем данные из файла
Case "C"
If hDbf.Fields(i).Dec <> 0 Then
ss = Mid(buf, pos, 256 * .Fields(i).Dec + .Fields(i).Length)
ss = dbfTrimString(ss, CLng(256 * .Fields(i).Dec + .Fields(i).Length))
End If
Case "D" ' dd/mm/yyyy
ss = Right$(ss, 2) + "/" + Mid$(ss, 5, 2) + "/" + Left$(ss, 4)
Case "L" ' Логическое поле T,Y или F,N
Select Case UCase$(ss)
Case "Y", "T": ss = "True"
Case "N", "F": ss = "False"
Case Else: ss = "?"
End Select
Case Else
End Select
' Назначаем данные
.Record.Data(i) = ss
' Определяем позицию следующего поля
pos = pos + .Fields(i).Length
Next i
End With
End Sub
'==============================================================
' Сохраняем данные 1 записи в таблице
'
Function dbfSaveRecord(hDbf As dbfHeader) As Long
Dim i As Long, p As Long, dbs As Database, rst As DAO.Recordset, buf As String, sn As String
On Error GoTo 999
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset(hDbf.TableAccess)
With hDbf
rst.AddNew
For i = 0 To .NumberFields - 1
buf = .Record.Data(i) ' Nz(Trim(.Record.Data(i)), " ")
sn = .Fields(i).Name
Select Case .Fields(i).Type
Case "C": rst(sn).Value = CStr(buf)
Case "D": rst(sn).Value = CDate(buf)
Case "M": rst(sn).Value = buf
Case "L": rst(sn).Value = CBool(buf)
Case "N", "F":
p = InStr(buf, ".")
If p Then buf = Left(buf, p - 1) & "," & Mid(buf, p + 1)
rst(sn).Value = CDbl(buf)
End Select
Next i
rst.Update
End With
rst.Close
Set rst = Nothing
Set dbs = Nothing
Exit Function
999:
Err.Clear
Resume Next
End Function
'==============================================================
' Программа для конвертации строки из Dos в Windows и наоборот
'
Public Function dbfReadDate(buf As String) As Date
On Error Resume Next
dbfReadDate = DateValue( _
1900 + Asc(Mid$(buf, 1, 1)) & "/" & _
Asc(Mid$(buf, 2, 1)) & "/" & _
Asc(Mid$(buf, 3, 1)))
Err.Clear
End Function
'==============================================================
' Программа для конвертации строки из Dos в Windows и наоборот
'
Public Function dbfStrConv(strData As String, buf1 As String, buf2 As String) As String
Dim i As Long, strChar As String, p As Long
' Конвертирование строки
dbfStrConv = ""
For i = 1 To Len(strData)
strChar = Mid(strData, i, 1)
p = InStr(1, buf1, strChar)
If p > 0 Then
dbfStrConv = dbfStrConv & Mid(buf2, p, 1)
Else
dbfStrConv = dbfStrConv & strChar
End If
Next
End Function
'==============================================================
' Обрезаем ненужные данные из строки dbf
'
Public Function dbfTrimString(strData As String, lngData As Long) As String
Dim p1 As Long, p2 As Long
' Конвертируем строку из Dos в Windows
strData = dbfStrConv(strData, alfaDos, alfaWin)
' Определяем пустые данные
For p1 = 1 To lngData
If Asc(Mid(strData, p1, 1)) >= 32 Then Exit For
Next
For p2 = p1 To lngData
If Asc(Mid(strData, p2, 1)) < 32 Then Exit For
Next
dbfTrimString = Mid(strData, p1, p2 - p1)
End Function
'<--End

Выпуск 35. Интеллектуальный поиск

  Новости
     22.02.2002. Вышла рассылка для специалистов "Профессионально об Access". Подробно рассматриваются 2 примера просмотра отчетов в форме, т.к. существующие версии Access 97-XP не позволяют просматривать отчеты в формах.
    22.02.2002. Добавились бесплатные примеры в файлы: la_find.mdb (3 интеллектуальный поиск), la_api.mdb (7 применение AdrressOf ), la_files.mdb (4 Чтение бинарного файла). Смотрите на сайте раздел: "Бесплатные коды".

Статья:  Интеллектуальный поиск
Автор:  Николай Малютин
Сообщение:
  
Предлагаемый метод предназначен для выполнения операции сравнения по приблизительным фразам. Например, если в большом списке поставщиков есть организация <ЗАО " Рога и Ка пыта" > (секретарша, вводя название в базу данных, сделала ошибку ;-), а Вы пытаетесь найти в нём по памяти <Копыта и Рога, ООО>, то при использовании традиционных методов поиска Вас, скорее всего, ждёт неудача. В предлагаемом решении Вы без труда сможете находить такие совпадения. Сам метод предложен Владимиром Кива, http://www.glasnet.ru/~vlak/similar/similar.html. В оригинале был приведен исходный код на C++ и библиотека. Я перевел код на VB и немного доработал, поэтому утилиту можно использовать в проектах БД
Дополнение от меня :
  Пожалуйста, посетите сайт, указанный выше, и изучите алгоритм поиска и лицензию на использование кодов на С++. Со своей стороны я только изменил название: "Нечеткое сравнение" на "Интеллектуальный поиск" и добавил пример 3 в файл la_find.mdb, где можно исследовать разные параметры сравнения текста. Прилагаемая программа работает с разными регистрами строк. Вот варианты примеров:
' 1. Сравнение с учетом регистра
' if IndistinctMatching(4, "test", "TEXT", vbBinaryCompare) > 40 then ...
' 2. Сравнение без учета регистра
' if IndistinctMatching(4, "test", "TEXT", vbTextCompare) > 40 then ...
Утилита IndistinctMatching возвращает число от 0 - 100, например, если число более 40, то можно говорить о совпадении фраз. Меняя это число, можно задавать разные условия поиска.
P.S. Я думаю, что тема интеллектуального поиска очень актуальная и интересная. Оригинально и то, что сам алгоритм и его реализация в VBA имеют короткие решения и не требуется каких-либо дополнительных словарей для сравнения. Попробуйте получше вникнуть в проблему, возможно и у Вас появятся еще идеи, так что тему еще можно продолжить ... 
Private Type RetCount
lngSubRows As Long
lngCountLike As Long
End Type

Public Function IndistinctMatching(lngMaxLen As Long, strStringMatching As String, strStringStandart As String, lngCase As Long) As Long
Dim gret As RetCount
Dim tret As RetCount
Dim lngCurLen As Long 'текущая длина подстроки

'если не передан какой-либо параметр, то выход
If lngMaxLen = 0 Or Len(strStringMatching) = 0 Or Len(strStringStandart) = 0 Then
IndistinctMatching = 0
Exit Function
End If

gret.lngCountLike = 0
gret.lngSubRows = 0
For lngCurLen = 1 To lngMaxLen
'Сравниваем строку A со строкой B
tret = MatchingStrings(strStringMatching, strStringStandart, lngCurLen, lngCase)
gret.lngCountLike = gret.lngCountLike + tret.lngCountLike
gret.lngSubRows = gret.lngSubRows + tret.lngSubRows
'Сравниваем строку B со строкой A
tret = MatchingStrings(strStringStandart, strStringMatching, lngCurLen, lngCase)
gret.lngCountLike = gret.lngCountLike + tret.lngCountLike
gret.lngSubRows = gret.lngSubRows + tret.lngSubRows
Next lngCurLen

If gret.lngSubRows = 0 Then
IndistinctMatching = 0
Exit Function
End If
IndistinctMatching = (gret.lngCountLike / gret.lngSubRows) * 100
End Function

Private Function MatchingStrings(strA As String, strB As String, lngLen As Long, lngCase As Long) As RetCount
Dim tret As RetCount
Dim y As Long, z As Long
Dim strta As String
Dim strtb As String
For z = 1 To Len(strA) - lngLen + 1
strta = Mid(strA, z, lngLen)
y = 1
For y = 1 To Len(strB) - lngLen + 1
strtb = Mid(strB, y, lngLen)
If StrComp(strta, strtb, lngCase) = 0 Then
tret.lngCountLike = tret.lngCountLike + 1
Exit For
End If
Next y
tret.lngSubRows = tret.lngSubRows + 1
Next z
MatchingStrings.lngCountLike = tret.lngCountLike
MatchingStrings.lngSubRows = tret.lngSubRows
End Function
Вопрос:  1738
Тема:      Чтение и сохранение данных бинарного файла
Пример: la_files.mdb (4 пример)
Сообщение:
  Подскажите, как можно получить произвольную часть бинарного кода файла и присвоить его некоторой переменной?
Ответ. Способ чтения файла достаточно простой и описан в документации. Сложности возникают при чтении данных в переменные и преобразование их к нужному виду. Ниже указан пример, который Вы можете использовать для загрузки, например, файла dbf и написания своего конвертера для чтения табличных данных в Access. Сначала Вам необходимо будет прочитать заголовок dbf файла, определить длину записи, а потом уже можно будет читать/сохранять их во внешнем файле. Полное описание программы дано в 4 примере файла la_files.mdb
' Описываем структуру записи
Private Type AppRecord
ID As Integer
Name1 As String * 20
Phone1 As Long
Date1 As Date
End Type

' Читаем бинарный файл
Private Sub butRead_Click()
Dim intFile As Integer ' Указатель на файл
Dim myRec As AppRecord ' Мои данные

intFile = FreeFile() ' Создаем указатель
Open Me.strPath For Binary As #intFile
Get #intFile, 1, myRec ' Читаем данные (1-номер позиции)
Close #intFile ' Освобождаем память
End Sub
Вопрос:  1741
Тема:      Применение пользовательской функции в API программе
Пример: la_api.mdb (7 пример)
Сообщение:
   Как в приведенном ниже коде правильно указать адрес вызываемой функции: lpFunction.
   Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, ByVal uFlags As Long) As Long
  Примечание. Данная функция необходима для запуска таймера, т.е. для выполнения каких либо действий в программе через равные промежутки времени. Аналог в "Панели управления" раздела "Назначенные задания".
  Ответ.
  Для определения адреса вызываемой функции служит оператор AddressOf , в документации он не описан. Вызов функции в VBA выглядит примерно так:
hTimer = timeSetEvent(uDelay, uResolution, AddressOf funTimerProc, dwUser, uFlags)
funTimerProc - эта Ваша программа и должна быть описана во внешнем модуле. Она имеет несколько параметров и использование ее дано в 7 примере la_api.mdb. Само описание функции выглядит так:
Public Function funTimerProc(ByVal uID As Long, ByVal uMsg As Long, ByVal dwUser As Long, ByVal dw1 As Long, ByVal dw2 As Long) As Long
Вопрос:  1746
Тема:      Использование dll программ
Сообщение: Хочу загрузить в Word следующие файлы: msgrRU32.dll, msth32.dll. Как мне это сделать?
Ответ. Эти библиотеки отвечают за грамматику в офисе: орфография, тезаурус, переносы. Ищите их в следующих папках.
c:\Program Files\Common Files\Microsoft Shared\Proof\MSTHRU32.DLL
c:\Program Files\Common Files\Microsoft Shared\Proof\1049\MSGRRU32.DLL
Библиотеки не будут работать в программе, если Вы не сможете их правильно зарегистрировать в реестре, т.е. надо сравнить ссылки в вашем реестре с другим, где установлен правильный - "русский" офис и "прописать" их у себя.
Примечание. Вопрос не очень точный, но можно предположить, что Вы возможно собираетесь использовать какие-то функции из этих библиотек. Стандартный способ применения ссылок такой. Откройте редактор VBA. Далее смотрите меню: Tools-References-Browse. Выберите необходимую библиотеку и просмотрите ее функции. В данном случае это невозможно сделать, и поэтому придется самому искать описание этих библиотек. Применение функций будет такое же как и в API интерфейсе.

Выпуск 34. Классы и защита базы данных

  Новости
   29.01.2001. Добавился пример la_prot1.mdb в Access коды.
   03.01.2001. Вышли новые версии программ "Склад и Реализация" и "Курсы валют". Ведутся  разработки заказных проектов с использованием оригинальных новинок в интерфейсе. Подробное описание будет дано позднее.

Вопрос:  1687
Тема:      Защита mdw - бесполезна?
Сообщение:
   • На www.access.nm.ru узнал новость о том, что защита с помощью файла рабочих групп mdw вскрывается мгновенно (проверено лично).  Как защищать базы теперь?
   • Недавно мне попалась небольшая статья по модули классов в VBA (статья относилась к Access 2000). Технологию создания и использования классов я понял, но преимущества использования классов непосредственно в Access так и не понял.
Ответ.
 •
Вообще защиту базы, а именно, объектов и таблиц стандартными методами желательно не производить. Используйте, например, метод RSA для защиты данных в таблицах.
  Рассмотрим другой вариант защиты, а именно, объектов базы данных и программного кода. Например, необходимо создать файл mdb, который можно было изменять пользователю, а некоторые программы из формы изменить было бы нельзя. В данном примере создается внешний класс для формы и размещается в mde файле, который используется как библиотека.
 • Применение класса выгодно также за счет экономии времени на разработку  событий для стандартных кнопок: ОК, Отмена, Добавить, Печать и т.п. Если у Вас будет 5-10 форм это уже оправдывает создание класса и описание событий объектов.
 • Полный программный код дан в файле: la_prot1.mdb (см. пример 11 и класс: clsProtForm )

' Описание внутреннего класса для формы. Разместите его в вашей форме.
Private mFrm As clsProtForm

Private Sub Form_Open(Cancel As Integer)
Set mFrm = New clsProtForm ' Создаем класс
Set mFrm.Form = Me.Form ' Устанавливаем ссылку
End Sub

' Это внешний класс для формы. Сохраните его в текстовом файле, а потом импортируйте из VBA. Обратите внимание на использование объектов c событиями, и именно, формы, кнопок и группы. Все события класса будут срабатывать ПОСЛЕ работы с пользовательским классом  формы.
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "clsProtForm"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Compare Database
Option Explicit

' Объекты с событиями
Private WithEvents clsFrm As Form ' Форма класса
Attribute clsFrm.VB_VarHelpID = -1
Private WithEvents butCancel As CommandButton ' Кнопка класса
Attribute butCancel.VB_VarHelpID = -1
Private WithEvents GroupSelect As OptionGroup ' Группа
Attribute GroupSelect.VB_VarHelpID = -1

' Свойства форм
Public Property Set Form(Value As Form)
On Error GoTo 999
' События для формы
Set clsFrm = Value
clsFrm.OnLoad = "[Event Procedure]" ' Событие для загрузки

' События для клавиш
Set butCancel = clsFrm.Controls("butCancel") ' Ссылка на кнопку
butCancel.OnClick = "[Event Procedure]" ' Устанавливаем событие

' События для переключателя
Set GroupSelect = clsFrm.Controls("GroupSelect") ' Ссылка на группу
GroupSelect.AfterUpdate = "[Event Procedure]" ' Устанавливаем событие

Exit Property
999:
MsgBox Err.Description
Err.Clear
End Property
Public Property Get Form() As Form
Set Form = clsFrm
End Property

' События формы
Private Sub clsFrm_Load()
subProgress "clsFrm_Load" ' Загрузка
End Sub
' События кнопок
Private Sub butCancel_Click()
subProgress "butCancel_Click" ' Нажатие кнопки отмена
End Sub
' События группы
Private Sub GroupSelect_AfterUpdate()
subProgress "GroupSelect_AfterUpdate. Значение= " & clsFrm.Controls!GroupSelect
End Sub

' Сообщение. Вывод данных в форму
Public Sub subProgress(strMsg As String)
clsFrm.Controls("Progress") = _
clsFrm.Controls("Progress") & "clsProtForm: " & strMsg & vbNewLine
End Sub

Вопрос:  1689
Тема:      Поиск в таблице
Сообщение:
Есть форма, в которую вносятся значения серии и номера. По значениям указанным в этих двум полям нужно найти сведения в другой таблице и отобразить на форме. Каким образом это можно организовать? Таблица в которой должен осуществляться поиск может быть очень большой.
Ответ. Желательно таблицу с данными ограничить путем создания запроса на выборку. Поставьте этот запрос (например, SELECT * FROM [ВСЕ Книги] WHERE [Тип]=1) вместо таблицы (запроса) [Мои книги] в примерах указанных ниже.
Пример 1
. В данном варианте постоянно меняется запрос. Таким образом на экране всегда будут отображаться только те записи (книги), которые необходимо Вам просмотреть.
Private Sub myBooks_Change()
Dim s As String
s = Me.myBooks.Text 'Определяем текст
If Len(s) <> 0 Then s = " WHERE Left([Книга]," & Len(s) & ") = '" & s & "'"
Me.myFind3.Form.RecordSource = "SELECT Книга FROM [Мои книги]" & s
End Sub
Пример 2 . В данном варианте при вводе первых символов включается программа поиска и курсор останавливается на первой подходящей записи (книге).
Private Sub Books_Change()
Dim rst As Recordset, frm As Form
Set frm = Me.myFind3.Form 'Выбираем форму
Set rst = frm.RecordsetClone 'Выбираем запрос
rst.FindFirst "([Книга] Like '" & Me.Books.Text & "*')=True"
If rst.NoMatch = False Then frm.Bookmark = rst.Bookmark
End Sub
P.S. Описание контекстного поиска дано в файле la_form.mdb, 3 пример
Вопрос:  1690
Тема:      Обновление подчиненной формы
Сообщение: Есть форма "X", содержащая подчиненную форму "Y" (тип - ленточная) и есть форма "Z". "X" и "Z" открыты в окне базы. Как организовать обновление данных в подчиненной форме "Y" при закрытии формы "Z"?
Ответ. Обновление данных в форме (запроса содержащего записи) производится через подпрограмму Requery, которую имеет любой объект Form. Поэтому, чтобы не было проблем с объектами в программах используйте явные ссылки (например, Me.Form, DAO.Recordset и т.п. ) В данном случае программный код разместите в модуле класса формы Z.
Private Sub Form_Close()
Forms("X").Controls("Y").Form.Requery
End Sub

Выпуск 33. Преобразование баз данных

С Новым Годом!
    Поздравляю всех с Новым Годом. Желаю успехов в учебе, в работе, в бизнесе и прекрасного настроения!

 Полезные ссылки
 

 Примеры баз данных
   22.11.2001. Добавился отличный пример по работе с формулами, т.е. используя объекты RichTextBox и DHTMLEdit Вы теперь можете написать не только любую формулу, но и сделать улучшенный дизайн  форм в Access. Автор программы Малютин Николай
   12.11.2001. В Access кодах добавился интересный пример по работе с графикой. График или текст в форме или отчете сохраняется во внешнем рисунке (мета-файле). Автор программы Малютин Николай.

 Новости для специалистов
28.12.2001. Вышли новые изменения к программе "Склад и Реализация". Налог с продаж и НДС для частных и юридических лиц учитывается в соответствии с новым законодательством. Стоимость программы - 50$, обновление 25$. Возможна поставка в полностью открытых кодах.
28.12.2001. Вышла новая рассылка для специалистов.   Примеры указаны ниже
 profi_interface.mdb Описание
  Создание триггера в таблице   Триггер-это хранимая процедура, которая автоматически выполняется при вставке, обновлении или удалении записи из таблицы. У таблицы Access нет событий, поэтому назначить событие ей не удастся. Предлагаемый метод позволяет обойти это ограничение. Решение можно использовать для создания более компактных и быстрых баз данных путем отказа от использования некоторых ленточных форм.
  Получение параметров окон   Этот пример показывает как получить параметры всех приложений Windows и окон Microsoft Access, а именно название окна и дескриптор, класс и текст. Используется для работы с api интерфейсом
Ссылки базы данных   Пример показывает как управлять ссылками текущей базы данных, а именно созданием, просмотром и удалением. Необходим для автоматического подключения нескольких внешних баз данных к центральному проекту.

  Преобразование баз данных
    Один из часто встречающихся вопросов в конференциях по Access проблемы работы с локальными версиями Access. Например, Вы работаете с русской версией Access 2000, а потом вдруг возникает необходимость запустить базу данных в английской версии AccessXP, вот тут и могут возникнуть "подводные камни". Хотя на первый взгляд база данных хорошо открывается и проблем с объектами нет.
       Известный "народный" способ лечения, что сначала лучше базу данных разработать в английской версии, а потом уже использовать его в локализованной, не так уж и хорош. С моей точки зрения лучше действовать наоборот. Рассмотрим это на примере небольшой ошибки. 
     Сущность ее. После преобразовании базы данных может возникнуть проблема при открытии таблицы с полями в виде списков (Combobox). Программа предупреждает Вас сообщением: "Слишком большое число" (или "The number is too large"). Сообщение появляется столько раз сколько у Вас определено полей-списков.
    Исследуя параметры списков, Вы приходите к удивительному выводу, что после преобразования у списков полей таблиц изменился размер. Он стал очень большим 57, 79 см (ListWidth=57,79см), о чем Access  и предупреждал Вас при открытии таблицы. Возникает предположение, что программа преобразования просто изменила размер элемента. Но с другой стороны Вы начинаете соображать, что все размеры элементов определяются твипами и следовательно при конвертации к локальной версии таких изменений быть не должно.  Используя отладчик (debag), можно придти к выводу, что размер списка поля ColumnWidths действительно не изменился, а отличие заключается лишь в правильном написании свойства поля базы данных. Например, в свойстве ColumnWidths хранится "2450twip" или = "2450твип". И так, если Вы работаете в английской версии и в свойстве поля хранится twip, то размер отображается правильно. Исходя из вышеизложенного можно сделать вывод. 
    Базу данных надо разрабатывать в локальной версии (поиск русских символов в свойствах объектов осуществить проще, чем английских), но при этом надо использовать при разработке названия объектов на английском языке. После того, когда база данных разработана, надо проверить свойства всех элементов базы данных (таблиц, форм, отчетов и т.п.) на наличие русских символов (Ascii код их размещается в диапазоне от 128 до 255). После этого выводите список этих элементов и принимаете решение об их изменении. Например, "твип" заменяете на" twip", "таблица" на "table" и т.п. Задача вывода информации об этих элементах не очень сложная, можно сказать даже тривиальная. Для полного решения ее используйте пример работы со списками. Он указан ниже. Дополнительно в этом примере список еще и корректируется, т.е. его ширина равняется сумме размеров колонок списка. Для преобразования базы данных в английский вариант запустите программу из макроса: fSetTableCombobox("twip"), если необходим русский вариант: fSetTableCombobox("твип")

Public Function fSetTableCombobox(strTwip As String, Optional strProgram As String)
Dim tdf As DAO.TableDef, i As Long
Dim dbs As DAO.Database, fld As DAO.Field, strWidth As String

On Error GoTo 999
' Определим параметр strProgram, если будем работать в текущей базе данных. В других случаях необходимо закомментировать строку.
strProgram = CurrentDb.Name

On Error Resume Next
Set dbs = DAO.OpenDatabase(strProgram)
For i = 0 To dbs.TableDefs.Count - 1
Set tdf = dbs.TableDefs(i)
If tdf.Connect = "" Then
For Each fld In tdf.Fields
If fVerifyFieldProperty(fld, "ColumnWidths") = 0 Then
strWidth = fld.Properties("ColumnWidths")
strWidth = fChangeSubString(strWidth, ";", "+") ' Подготовливаем строку к расчету
fld.Properties("ListWidth") = Eval(strWidth) & strTwip
End If
Next
End If
Next
Err.Clear
dbs.Close
Set dbs = Nothing

Exit Function
999:
MsgBox Err.Description, vbExclamation, "Error: " & Err.Number
Err.Clear
End Function

' Функция проверяет наличие свойства
Function fVerifyFieldProperty(fld As Field, strName As String) As Long
Dim prt As DAO.Property
On Error GoTo 999
Set prt = fld.Properties(strName)
fVerifyFieldProperty = 0
Exit Function
999:
fVerifyFieldProperty = Err.Number
Err.Clear
End Function

' Замена подстроки
Public Function fChangeSubString(sFull As String, sOld As String, sNew As String) As String
Dim l As Integer, p As Integer, m As Integer
fChangeSubString = sSQL
If sOld = sNew Then Exit Function
m = Len(sOld)
l = Len(sSQL) + m
Do
p = InStr(1, sSQL, sOld)
If p > 0 Then sSQL = Mid(sSQL, 1, p - 1) + sNew + Mid(sSQL, p + m, l)
Loop While p > 0
fChangeSubString = sSQL
End Function

Выпуск 20. Борьба за скорость

Введение.
    В этом выпуске рассказывается о некоторых вопросах, связанных с увеличением скорости работы базы данных, продолжаются короткие уроки для начинающих и даются ответы на вопросы по Access.


Новости магазина "Лидер Access".
   1. Вышла новая программа "Курс 2000", версия 4.3. Назначение ее - быстрое получение курсов валют из Центробанка. Теперь Вы можете ��аспечатать календарь для любого курса валюты, а также улучшились характеристики программы по получению GBR, FRM и FIM. Программа распространяется бесплатно, но только для Access 2000. Вариант программы с возможностью чтения данных за любой период стоит 300 рублей. Открытый код VBA для добавления в Вашу складскую или банковскую программу стоит 300$.
   2. В прайс-листе появился таймер для профессионалов. Обязательно посмотрите его использование. Ссылки на программу и общий вид указаны ниже. Его свойства: имеет профессиональный дизайн, позволяет останавливать загрузку данных, свободно передвигается по желанию пользователя, легко управляется из VBA, не останавливает другие задачи пользователя, минимально загружает процессор. Применяется не только для отображения времени выполнения длительных задач в Access, но и для демонстрации Ваших профессиональных качеств. Цена 75 рублей.
   3. Еще один код, который распространяется магазином: Печать в Access 2000. Программа разработана с использованием API функций на языке Visual Basic для Microsoft Access 2000. После изучения кода Вы будете уметь получать информацию об установленных для разных операционных систем Windows принтерах и факсах, назначать любой из них по умолчанию (главным). Программа будет полезна в первую очередь разработчикам Access программ, создающим профессиональные приложения. Загрузите mde-пример и посмотрите его в работе. Цена 20 рублей.


Коды для Access 2000
   I. Файл la_form1.mdb. Добавлены следующие примеры. 16. Сумма прописью. Программа будет полезна для для разработчиков платежных поручений, т.к. добавлены решения в соответствии с последними указаниями Центробанка. 18. Диспетчер связанных таблиц. Данная программа заменяет стандартный диспетчер Access своим. 19. Цветные поля в форме. Показан пример, позволяющий форматировать поля, строки форм в зависимости от разных условий задачи. 20. Форматирование полей в форме. Небольшой пример на тему форматирования поля.
   II. Файл la_table1.mdb. Добавлен пример 11: "Сравнение свойств поля базы данных". Пример показывает встроенные свойства поля и те, которые Вы должны создать при программировании полей таблицы.
   III. Файл la_report1.mdb. Добавлен пример 16: "Изменение размеров страниц отчета". Пример показывает использование свойства отчета PrtDevMode. При подготовке использована справочная система Access.
   IV. Файл la_automat.mdb Добавлены примеры серверов автоматизации. 01. Рассылка почты через Outlook. Пример показывает как рассылать почту пользователям из Access. 02. Создание документа Word. Простой пример создания документа Word из Access.


Access 2000. Урок 2. Общая информация о таблицах
    Одним из самых главных объектов Access являются таблицы[1]. Удобство работы с ними и обеспечило громадную популярность этой базы данных. Условно таблицы можно разбить на две группы: внутренние и присоединенные из других файлов, например, mdb, dbf, db и т.п.
    Существует такое правило, что при сохранение информации в таблицах желательно, чтобы каждая строка была уникальной. Это достигается путем установки первичного ключа[2]. Он может состоять из одного или нескольких полей[3] таблицы. Если Вы не можете назначить подходящий ключ, то используйте поле Счетчик[4]. Использование таблиц без ключей возможно, но я Вам не рекомендую это делать на "реальных" базах данных.
    В Access есть несколько способов создания таблиц. Например, 1 - в режиме конструктора, 2- c помощью мастера, 3- путем ввода данных, 4- через запрос SQL[5], 5- с применением функции VBA[6]: CreateTableDef. 6- путем импорта таблиц из других баз данных, смотрите TransferDatabase. Каждый из этих способов имеет свои плюсы и недостатки, но какой лучше выбрать на этапах разработки базы данных решать Вам. Мы же остановимся сейчас на самом популярном - первом способе: "Создание таблицы в режиме конструктора".
    В этом режиме Вы визуально можете создать поля. Важно уметь давать короткие имена им. Например, [Номер документа] = [Nдок], [Название организации] = [Фирма], [Единица измерения]=[ЕдИзм]. Это связано с тем, что применяя короткие имена полей, Вы тем самым уменьшаете длину запросов и база данных работает быстрее, да и ошибок будет меньше.
    Кроме этого в конструкторе можно назначить свойства[7] полям. Например, "Размер", "Описание", "Подпись" и другие. Свойств полей в базе данных может быть очень много. Посмотрите пример 11 в файле la_table1.mdb, там указано, что при создании поля типа Дата/Время создается сразу 24 свойства. Еще четыре, а именно, Описание-Description, Маска ввода-InputMask, Формат поля-Format, Подпись-Caption являются "бутафорией", т.е. Вы их видите в конструкторе таблицы, но на самом деле их нет. Программисты Microsoft сделали это за тем, чтобы обеспечить минимальный размер базы данных. Из этого заключения следует, что эти свойства лучше не заполнять. Но это неправильно, например, без свойства "Описание" будет сложно понять назначение полей Вашей таблицы. Пример привожу за тем, чтобы Вы при создании таблиц программным путем помнили, что эти свойства сначала создаются, а только потом уже изменяются, иначе будет сгенерирована ошибка.
   В заключение хочу сказать, что проектирование таблиц - это искусство, и только "опыт" может подсказать Вам, как лучше их разрабатывать.
Словарь
   • [1] Таблицы (Table) - основной объект базы данных.
   • [2] Первичный ключ (PrimaryKey) - свойство таблицы.
   • [3] Поле (Field) - главный объект таблицы.
   • [4] Счетчик (AutoNumber) - специальное автозаполняемое поле в базы данных.
   • [5] VBA (Visual Basic For Applications) -язык программирования Бэйсик для офисных приложений.
   • [6] SQL (Си'квэл, Structured Query Language) - язык создания запросов к базе данных.
   • [7] Свойство (Property) - параметр структуры поля базы данных

Ответы на вопросы


 

Вопрос. Как можно увеличить скорость программы?
    Искал как-то я в Интернете решение проблемы "Переменная высота строк в отчете". Серьезной информации по отчетам не было, нашел только решение с подсчетом символов в поле. Применять его было нельзя из-за сложного алгоритма. Самостоятельно вышел на изящное решение, что надо рисовать прямоугольник вокруг поля при обработке события отчета Print. Смотрите файл: la_report.mdb, подписка 13 от 10.10.2000. Сейчас "обкатываю" еще одно оригинальное решение на эту тему. Заглянул на всякий случай в Рунет и нашел, что один "гений" в алгоритме по рисованию поля заменил шустрый оператор if else на "новейшую мину замедленного действия" - IIF(двойной если). А "Профи" настоятельно не рекомендуют применять его в basic- программах. Даю расшифровку фразы. "Миной замедленного действия" IIF() можно назвать потому, что он значительно моложе и на 70% медленнее оператора if else, да еще при неосторожном использовании приводит к "сваливанию" программы. Это анти-решение и подсказало мне опубликовать несколько коротких фраз по оптимизации кода. Повышение производительности базы данных в процентах указано в скобках. Информация сокращена до минимума. Надеюсь Вам будет понятно, о чем идет речь, но если, что неясно - пишите.
01. Используй оператор if else, вместо IIF() [70%]
02. Используй Long, т.е. Long лучше Byte, Integer и, конечно, Variant [20%,50%]
03. Применяй If-Else, чем Switsh, Shoose [50%]
04. Лучше проверяй строку так Len(s) = 0, чем s = "" [40%]
05. Лучше инициализируй строку так s = vbNullString, чем s = "" [65%]
06. Если возможно пиши так s = "AB", чем s = "A" & "B" [85%]
07. Вставляй строку в текст так Mid$(s,3,4)="like", чем s = Left$(s,2) & "like" & Mid(s,7) [45%]
08. Сравнивай строки так If StrComp(s1,s2,vbTextCompare) =0 then, чем If Ucase(s1) = Ucase(s2) [55%]
09. Лучше используй $-функцию, т.е. Left$ лучше Left [40%]
10. Цикл For...Next работает быстрее Do...Loop [50%]
11. При обработке целых чисел пиши j=i\10, чем j=i/10 [30%]
12. Точнее объявляй объекты: as CommandButton лучше As Control, еще лучше as Object [90%]
13. Цикл For Each...Next лучше, чем цикл For...Next для семейств объектов [98%].
14. Цикл For ...Next лучше, чем цикл For Each...Next для массивов [25%].
P.S. 1. Все тесты на скорость придумали и провели для Access 2000: Кен Гетц, Пол Литвин и Майк Гилберт. За что им большое спасибо.
2. Запомните наизусть фразу из документации по VBA, самый короткий код - не самый быстрый. Есть еще предложения по оптимизации кода, их я опубликую позже.
Вопрос 27. Помогите, пожалуйста, понять, есть ли возможность из приложения Access отправить Outlook Task Request?
Вопрос 81. У меня вопрос. Я подрабатываю в службе знакомств. Создал небольшую базу данных, где пока только наши клиентки (создал по примерам "Борей", достаточно симпатично). Я хочу что бы можно было связать каждую девушку с отдельным клиентом. Нужно что бы входящие и исходящие письма с каждым клиентом можно легко достать и отсылать их по e-mail из ACCESS
Вопрос 82. Расскажите, пожалуйста, как можно автоматизировать рассылку новостей (с помощью OutLook или средствами самого Access). В базе данных мы имеем определённый набор адресов электронной почты (который постоянно пополняется) и набор новостей. Как адреса так и новости разбиты на категории и их количество не постоянно. Определённые категории новостей рассылаются определённым категориям клиентов с учётом уже отправленных новостей и времени вступления в клуб. Поэтому такой сервис крайне необходим.
  Ответ. Когда я получил первую информацию на эту тему я подумал, что кто-то хочет стать спамером. Но после этих двух вопросов стало ясно, что проблема важна для многих. Поэтому и дал решение в примере N1 в файле: la_automat.mdb. Чтобы Вам не скучно было изучать Outlook вставил вымышленное письмо спамера к своим "родителям". Но адрес email рассылки указан реальный. От адресата несколько раз приходили письма купить базу данных клиентов и рассылать рекламу, т.е. стать спамером.
  О проблеме. Ее решают через применение клиента автоматизации. Короткий код я привожу здесь, чтобы Вам была понятна сама идея.
Set app = New Outlook.Application 'Открываем Outlook
Set itm = app.CreateItem(olMailItem) 'Создаем сообщение
itm.Subject = Me.Subject 'Определяем тему письма
itm.Body = Me.Body 'Вставляем текст письма
itm.Attachments.Add Me.File 'Присоединяем файл
itm.Recipients.Add Me.Email 'Добавляем адрес рассылки
itm.Send 'Посылаем письмо
app.Quit 'Закрываем Outlook
Более подробно, с использованием таблицы, где можно хранить электронные адреса и письма для рассылки смотрите в файле: la_automat.mdb.
 Вопрос 72 (16.11.2000). Буду признательна, если поможете справиться со следующей проблемой. Требуется выделять другим цветом поле или строку в ленточной форме в зависимости от конкретного значения поля текущей строки.
   Ответ. Эту проблему Microsoft решила только в версии 2000, в 97 она есть. Программисты Microsoft разработали три варианта условий при котором форматируется поле формы в Access: 1- в зависимости от его значения, 2 - в зависимости от некоторого выражения, которое может быть связано с другими полями, 3 - при получении фокуса, т.е. при входе в поле. Максимально в каждом варианте Вы можете рассматривать 3 условия форматирования. Чтобы полностью закрыть эту тему, посмотрите пример N19 в файле: la_form1.mdb
Вопрос 50. Подскажите, пожалуйста, как в вычисляемом поле запроса "Access" избавиться от 15 - 18 знаков после запятой? В вычисляемом поле перемножаются данные из поля с "длинным целым" (пробовал изменить на "целое") на данные из поля с "плавающей точкой (4 байт)" (пробовал и на 8 байт).
  Ответ.Игорь Макеев Format или написать функцию округления
Виктор Конюков Пример 20 на эту тему я привел в файле la_form1.mdb Его можно использовать для тренировки или быстрого просмотра разных форматов поля формы.
Вопрос 56. В одном из прошлых выпусков рассылки Вы упомянули о том, что Вам в программе "Склад и Реализация" удалось реализовать постоянную скорость доступа к данным в течение года. Насколько я понимаю, в данном случае скорость обработки данных не зависит от их объема, чего в случае работы с большими (по числу записей) таблицами быть НЕ МОЖЕТ. Объясните, пожалуйста, в общих чертах, как Вам удалось добиться такого результата, или пришлите ссылки на ресурсы Internet. Если Вы решили разбивать большие (по количеству записей) таблицы на несколько одинаковых небольших таблицах, тогда поясните, как Вы реализовали скоординированный доступ к этим таблицам.
   Ответ. Это ноу-хау. Подробности дать не могу. Сами понимаете, все мгновенно "раcтащат" наши "гении", и пользы никакой людям не принесут, да и сами ничему не научатся. Но кое-что рассказать можно. Во первых о ссылках. Есть у меня есть раздел на сайте "Ресурсы Access". Используя его, Вы можете выйти на любой сайт или архив программ в Рунете. Но сразу скажу, если отбросить файлы, которые копируют другие идеи, то информации получиться очень мало. А методы повышения скорости и оптимизации применения большого числа файлов и таблиц базы данных вообще никто не рассматривает. Ну а теперь о самой методике.
    Данная технология разрабатывалась для предприятий с низким производственным потенциалом, т.е. людей без высшего образования уже в зрелом возрасте. Им тратить время на изучение новых программ, SQL серверов или копаться в таблицах с 20 тысячами записей проблематично. Было ясно, что даже если им прикажет директор, и они полностью согласятся с ним, самостоятельно ничего изучать не будут и даже пальцем не пошевелят. Поэтому задача была поставлена такая, минимум данных, приличная скорость работы с компьютером и максимум автоматизации.
   Решение проблемы началось не с программирования, а с изучения методов расчета себестоимости, учета кассовых и банковских операций. Проанализировав проводки в документах предприятия, и частоту их использования, были вычислены таблицы, которые нужны складу, банку и кассе. Определена степень их важности и место хранения в базе данных. Установлены между ними связи. Только после всего этого разрабатывались, формы, запросы отчеты.
   Некоторая информация по структуре VBA. Общее число программ в модулях более 200. Чтобы управлять автоматически файлами, была создано специальное ядро системы. От репликации Microsoft пришлось отказаться и разработать собственный вариант. Вот пример ее применения. Если необходимо в эталонной базе данных добавить поле или изменить его размер в сторону увеличения, то при обращении к рабочей базе функция репликации должна это делать автоматически. А вот уже обратно, т.е. удалить поле или уменьшить его размер, она должна это делать только в ручном режиме, так как возможна потеря данных. Ядро системы должно без участия работника переводить остатки, вести нумерацию документов во всех файлов. Много чего пришлось решать, все коротко и не расскажешь. Тяжелый труд, применение клиент - сервер архитектуры проще. Но самое главное - это хороший результат. Дело в том, что увеличилась не только скорость базы данных, но сократилось время внедрения до 1 дня. Как это происходит. Приходит заказчик со своим прайс - листом, при нем вводится информация и печатаются все накладные, остатки и другие документы по складу. Задается вопрос, можно ли изменить в конструкторе отчет или форму. Показывается как это сделать. Если клиент - серьезный "покупатель", то договаривается об оплате, если "интересующийся", то просит схему таблиц или демо-версию. Естественно, никто ему это не даст, и он уходит расстроенный. Правда сейчас я планирую для тех, кто собирается переходить c dbf программ на Access опубликовать несколько примеров из сборника. Думаю, что и конкурентам что-то от этого перепадет.
   Работа над программой постоянно совершенствуется. Тестируется новая версия, в которой свободно можно будет изменять внешние отчеты и формы, не думая о привязке таблиц. Всем старым покупателям версия программы будет рассылаться бесплатно, при этом добавление новых таблиц и полей произойдет автоматически.
Вопрос 59. Вот столкнулся с такой проблемой. Как по Access 97 (из своей программы) вызвать - Диспетчер связанных таблиц? Как в Access 2.0 делается знаю, но в 97 это уже не проходит.
Вопрос 64. При разделении базы на mde и mdb файлы связи с таблицами можно обновить через диспетчер связанных таблиц. А как это сделать программным путем?
  Ответ. В принципе решить задачу очень легко. Сначала, найдите пункт меню, используя его имя или код в элементах управления. Далее выполните для него команду execute. С другой стороны, для серьезной программы лучше разработать свой диспетчер связанных таблиц.  Пример 18 на эту тему я привел в файле: la_report1.mdb. Дополнительно там, Вы найдете подробное решение Дмитрия Чернова. Используя 2 идеи Вы полностью решите свои проблемы.
Вопрос 83 (21.11.2000). Здравствуйте. Мне очень понравилась Ваша рассылка, но в силу определенных обстоятельств я пользуюсь Access97. Могу ли я относить описанное в Вашей рассылке к этой версии программы? Заранее благодарен
   Только частично, некоторых функций нет в Access 97.
Вопрос 86 (22.11.2000). Случилась такая проблема: при выводе в поле отчета (и формы) результата строковой функции (и string, и variant), содержащей русские буквы, выводятся знаки вопроса (на месте русских букв). Шрифты -- разные: от Arial до различных Type1. При этом вывод =CStr("русские буквы") -- без проблем. Пробовал Access 97 на w2000en, w95en, w98ru. Все с IE5 -- в доке встречал упоминания о кодировке рядом с IE; без IE5 под рукой ничего нет.
  Ответ. Вообще надо проверить работу Вашей программы на одном офисе, т.е. где только находится Access 97 или Access 2000. Связано это с тем, что у них другой метод работы с символами. У меня это встречалось, но очень редко. Исправлял повторным вводом символов. P.S. Второй способ - попытайтесь из базы данных сделать микро-код и протестировать.
Вопрос 86а (23.11.2000). Попробовал привязать Вашу функцию "Сумма прописью" к платежке. Все вроде хорошо, но заметил что при вводе суммы ровно 1000 руб. (копейки роли не играют) и далее кратно 1000, то есть без рублей после тысячи то в результат попадает: "Одна тысяча ХХ копеек" (ХХХ тысяч/тысяча), а хотелось бы получить "Одна тысяча рублей ХХ копеек". Такая же история и с миллионами и т.д. Посмотрев код функции я не нашел быстрого способа исправить это. Наверное придется писать условия для всех трех блоков (тысячи, миллионы, миллиарды)
   Ответ. Когда я публикую код, вытаскивая его из какой-нибудь своей программы, то я сокращаю его до минимума, чтобы было понятно логику программы. Код для "Суммы прописью" я добавил, посмотрите его и сравните со старым (раздел "Архив программ"). Решение не очень сложное. Мой совет. Подумайте немного сами, может получится и у Вас.
Вопрос 87 (23.11.2000). У нас в банке требуют при печати платежки, чтобы в графе сумма цифрами (поз.7) при указании суммы с копейками равными "00" стоял разделитель "=" между рублями и копейками, а при всех других случаях стоял "-". Я не понял до конца каким способом сделать это безболезненно для моей структуры (не добавляя доп. полей в таблицы и др.).
   Ответ. Тема "Платежное поручение" - неисчерпаема. Для тех, кто только вступает в ряды разработчиков Access и собирается помочь решить им эту сложную задачу, я добавил в файл la_form1.mdb способ отображения суммы прописью, а также форматирование числа с разделителем разрядов по новым требованиям Центробанка.
Вопрос 92 (23.11.2000). Думаю следующий вопрос будет интересен многим.  Не подскажете ли Вы, как Отчете из двух таблиц, (главной и подчинённой) отобразить записи в подчинённой таблице не в столбик, например:
       поле главной таблицы
       поле подчинённой таблицы(запись 1)
       запись 2
        ....)
       а в строчку, например,
       поле главной таблицы
       поле подчинённой таблицы(запись 1, запись 2 ....)
   Ответ. Посмотрите пример как добавить поле в отчет mde файла. Принцип добавления полей вдоль строки такой же.
Вопрос 93 (23.11.2000). Возможно ли создание вычисляемых полей в таблицах Access ?
  Возможно.
1 способ. /Новая запись/ Вставьте функцию по умолчанию для поля. При создании новой записи в ваше поле будет записываться результат, определенной этой функцией.
2 способ. /Существующая запись/ Составьте для поля список на основе запроса, который будет использовать вашу таблицу. В таблице поле придется обновлять вручную, но если известен результат для него, то это не очень сложно. Примеры такой таблицы в mdb формате приведу позже.
Вопрос 94 (24.11.2000). Здравствуйте, у меня возникла проблема: необходимо посчитать срок (из одной даты вычесть другую) в годах, месяцах, неделях.
Стандартная операция возвращает целое число - количество дней. Можно конечно перевести в месяцы, но как быть, если год високосный?, если в этот промежуток времени попадает 29 февраля?
  С датами в Access работают как с целыми числами. Например, если Вам надо определить последнее число месяца делается это так.
d = Date 'Текущая дата
m = Month(d) 'Определяем месяц
y = Year(d) 'Определяем год
DLast = DateSerial(y, m + 1, 1) - 1 'Последний день месяца
Вопрос 95 (24.11.2000). DoCmd.OutputTo acOutputReport, Name_Report, acFormatTXT, , False если юзер нажмёт отмена в диалоге "Выбора пути сохранения файла",
Access выдаст окно с предупреждающим сообщением. Можно ли как-нибудь избавиться от него?
Ваш код можно улучшить таким образом:
On Error Resume Next
DoCmd.OutputTo acOutputReport, Name_Report, acFormatTXT, , False
Err.Clear
Вопрос 96 (24.11.2000). При разработке программы в MSA97 столкнулся с тем, что невозможно выполнить инструкцию DoCmd.OpenReport "MyReport", ,"MyQuery", если MyQuery является объединенным запросом. Может быть, использовать свойство RecordSourse для отчета? Пробовал, не получается. Даже будучи открытым в режиме предварительного просмотра, отчет не позволяет менять свое свойство RecordSource,
т.к. процесс печати, уже, мол, запущен. И советует изменять это свойство в процедуре обработки события Open. А это, как ни крути, означает, что придется сохранять отчет для этого запроса под другим именем, выставлять у него свойство RecordSource, и все это как-то... нерационально. А разница всего-то в источнике записей. Уверен, должно быть красивое решение, и эта мысль не дает мне покоя. Помогите идеей, если возможно.
   1. Вид команды такой: DoCmd.OpenReport "МойОтчет"[, "Вид отчета"][, "Запрос отчета"][, "Условие отбора записей"]. Если у Вас правильно составлен запрос и условие отбора, то все работает.  Таким образом Ваша команда может выглядеть следующим образом:
DoCmd.OpenReport "MyReport", acViewPreview, "MyQuery", "[Number]>10"
   P.S. Необходимо перед открытием отчета проверить наличие запроса "MyQuery" в базе данных, если он открывается, то все будет работать. Конечно поле [Number] можно из запроса и команды убрать.
   2. После начала форматирования отчета нельзя изменить его запрос, но можно применить к нему фильтр, т.е. из всех записей отобрать только нужные. Как использовать фильтр (условие отбора) описано в примере 15 файла: la_report1.mdb
Вопрос 97 (24.11.2000). А как узнать какие названия цветов может идентифицировать Access и можно ли изменять таким образом размер шрифта и сам шрифт для отдельных столбцов
   К примеру 06 в файле: la_table.mdb. К сожалению в самой таблице, в отдельном столбце, изменить шрифт не удастся. Это можно сделать только для всей таблицы. Откройте ее, поставьте курсор на заголовок окна или столбца и нажмите правую клавишу. Перед Вами отобразится меню, где Вы сможете изменять свойства таблицы или поля. Всего при форматировании таблицы Access поддерживаются 16 цветов (Красный (Red), Черный (Black) и т.п.) Дополнительно прочитайте об этом в справке по форматированию поля.
Вопрос 98 (24.11.2000). Вопрос 67 (16.11.2000). В Access2000 произвожу экспорт таблицы в формат Paradox, нормально экспортирует, но кодировка получаемой базы .db почему-то 866, не подскажите как сделать 1251. Если я правильно понял, суть вашей рекомендации:
HKEY_LOCAL_MACHINE\Software\Microsoft\Jet\4.0\Engines\Xbase]
"
DataCodePage"="OEM"
При работе с другими dbf файлами надо изменить OEM страницу на ANSI
"DataCodePage"="ANSI"
- соответственно, вместо Xbase - Paradox. Попробовал, в результате во-время сохранения: Непредвиденная ошибка драйвера внешней базы данных <10018>. Посмотрел help на Access2000, относительно DataCodePage: "Этот параметр используется только в том случае, если на данном компьютере не установлено приложение BDE." В моем случае BDE установлено и значение LANGDRIVER выбрано "Pdox ANSI Cyrillic". Не посоветуете, что можно еще сделать.
   Вы неправильно сделали изменение. Ключ Xbase устанавливает Access, и менять его на Paradox нельзя. Исправить в реестре можно только OEM или ANSI, указано зеленым цветом. В вашем случае я бы попробовал изменить ANSI в параметрах секции ..\Jet\4.0 на OEM. Например, написать "Pdox OEM Cyrilic". Рекомендацию не проверял, так что будьте внимательны при изменении реестра. Во вторых, при конвертации строк из одной базы данных в другую можно использовать функцию: StrConv(myText, vbUnicode).
Вопрос 99 (24.11.2000). Есть форма, в ней Календарь и два текстовых поля. Выбираем дату в Календаре - щелчок по кнопке - дата в ТextBox1(начальная дата), снова выбор в Календаре - щелчок по кнопке и дата в TextBox2 (конеч. дата). Теперь вопрос: Как открыть отчет, используя даты в TextBox1,TextBox2 и оператор BETWEEN. С одной датой работает: DoCmd.OpenReport "Отчет1", acPreview, "", "[Запрос1]![Дата]=[Forms]![Форма1]![TextBox1]" и с OR работает:
DoCmd.OpenReport "Отчет1", acPreview, "", "[Запрос1]![Дата]=[Forms]![Форма1]![TextBox1] or [Forms]![Форма1]![TextBox2]", а какой синтаксис у BETWEEN? Создать отчет на основе запроса с BETWEEN нет проблем! Но очень хочется так как сказано выше!
   При использовании запросов надо использовать американский стандарт записи, т.е. формат такой даты такой: #месяц/день/год#. Вот пример на эту тему:
SELECT * FROM [Мои книги] WHERE (((Дата) Between #9/14/2000# And #9/19/2000#));
В вашем случае я бы написал функцию usDate, которая бы конвертировала дату из списка в другой стандарт, т.е. запрос будет такой: DoCmd.OpenReport "Отчет1", acPreview, "", "(((Дата) Between " & usDate([Forms]![Форма1]![TextBox1]) & " And " & usDate([Forms]![Форма1]![TextBox2]) & "))"
Вопрос 100 (24.11.2000). Можно ли восстановить удалённые файлы в *.dbf ? Помогите!!!!!!
  Во первых, если Вы удалили файл dbf, то посмотрите его в корзине или используйте другую программу восстановления, например, утилиты Нортона.
  Во вторых, если Вы удалили записи в dbf и файл не сжали, то их можно восстановить. Каждая запись в dBase не удаляется, а отмечается флажком '*'. Поэтому Вам надо заменить '*' на ' ', тогда она появится. Программ на эту тему очень много, посмотрите в интернете или используйте какой-нибудь программный пакет для работы с dBase. С другой стороны, если Вы часто работаете с dBase файлами, напишите такую программу сами. Это не сложно. Файл dbf имеет самую простую структуру и очень полезен для изучения таблиц баз данных.
  P.S. За вопрос номер 100 спасибо. Желаю Вам огромных успехов в изучении dBase.
Вопрос 102 (27.11.2000). Результатом моего запроса являются два поля, например: ProductName и UserName. Мне же необходимо: ProductName и UserQuantity, т.е. для каждого продукта подсчитать, ск. Users его используют. Как можно сосчитать , сколько раз встречаются строки с каждым ProductName, упомянутым в таблице или запросе ? М.б. это можно сделать, "привязав" результат запроса к отчету ?
   1. Используйте запрос на группировку, например, SELECT ProductName, Count(ProductName) AS [UserQuantity] FROM [myTable] GROUP BY ProductName;
   2. Можно сделать группировку по ProductName в отчете, тогда запрос 1 не потребуется.
Вопрос 103 (27.11.2000). 1.Как сравнить в MS ACCESS две таблицы
  импортированные из EXCEL. Каждая из них содержит 13 столбцов (Название Индекс  Город Адрес  ФАМИЛИЯ ТЕЛЕФОН и т.д) и около 3000 строк - данные по организациям.   По сути это часть базы наших подписчиков. При этом почти все данные содержащиеся   в строках и столбцах в обоих файлах совпадают, за исключением 10% данных. Некоторые названия
организаций только похожи например в одном файле-таблице: "ООО Олала \ 400058 \Волгоград\Ул.  Костюченко,  49 \ кв.  1", в другом файле-таблице: "Опава ООО \ 400058\ Волгоград \ Ул. Костюченко,43  кв.  1".
  1. Для этого создается 3 таблица и индексируется по сравниваемым полям. Далее, через запрос на добавление, данные из первых 2 таблиц перезаписываются в третью. Индекс не позволит записать лишние записи в новую таблицу.
  2. Остается только вручную отобрать нужные записи. Писать программу анализирующую Ваши строки достаточно сложно.
Вопрос 104 (27.11.2000). Как удалить одинаковые данные из одной и той же таблицы. Например: строка1 "ООО Опава \ 400058 \Волгоград\Ул  Костюченко,  49 \ кв.  1"  строка 195 "ООО Опава \ 599999 \Москва\Ул  Костюченко,  49 \ кв.  1" При этом до удаления каждой строки обязательно чтобы программа спрашивала у пользователя удалять ли конкретную строку.   
  1. Надо написать запрос на группировку (см. пример 102) и отобрать записи, где счетчик <> 1
  2. Откройте этот запрос в программе на VBA и для каждой записи установите проверку на удаление.
  3. Если пользователь согласился на удаление строки, далее составьте запрос на удаление, используя данные из предыдущего запроса на группировку.
  P.S. Некоторые примеры по составлению запросов есть на сайте.
Вопрос 105 (27.11.2000). При импорте из файла EXCEL данные типа: июль01 вообще не импортируются. Как быть?
   Надо написать конвертер для перевода текстовых данных в тип Дата, функция - CDate. Пример конвертера есть на сайте.
Вопрос 107 (27.11.2000). • Написана база данных, которая должна работать под сетью (2 компьютера, один из которых является сервером). • Создана папка общего доступа, в которой я разместил таблицы. На каждом компьютере создан файл mdb, содержащий формы, модули, запросы и ссылки на общие таблицы, находящиеся на
сервере. • Но работа программ происходит настолько медленно, что с базой данных просто невозможно работать: - Загрузка формы происходит около 1 минуты. - Переход из записи на запись происходит около 5 секунд. Это несмотря на то, что я проанализировал в мастере
быстродействие, оптимизировал все, что только можно, и создал mde - файл.
    Эта же программа работает на порядок быстрее, если формы не отделять от таблиц, а создать единственную копию на сервере, к которой открыть доступ с обеих компьютеров. Но тогда возникают проблемы с блокировкой данных, при совместной работе, и проблема с открытием основной формы (если на втором компьютере она уже открыта, необходимо закрыть ее,
дать возможность открыть ее на 1-м, после этого открыть ее с окна базы данных).
   Здесь Вас может только выручить тест на скорость. Создайте у себя базу данных mde c одной формой, а на сервере разместите mdb с таблицей. Если скорость медленная, то надо настраивать программное обеспечение сервера (приоритеты доступа), если высокая, то надо копать у себя программный код (упрощать запросы, открывать их после загрузки формы и т.п.)
Вопрос 106 (27.11.2000). В Access в запросах используются различные функции по подмножествам, типа суммы, среднего, максимального и др. Так вот, есть ли там такая функция, которая бы суммировала не числа из подмножества, а строки, т.е. возвращала сумму строк. Она бы мне очень пригодилась.
  Изучите работу функции Count. Например, Count(*), Count([N]) и т.п. Данная функция возвращает число повторяемых строк в запросе.
Вопрос 108 (28.11.2000). В запросе поле МЕМО обрезается... Это происходит только в Access 2000... до конвертации подобных проблем не было. Почему??? И как это исправить? Все отчеты использующее это поле получаются неполные... Если есть возможность ответить мне сегодня, буду очень признательна!
   В поле Memo может быть 65335 символов. Лично у меня запросы и отчеты, созданные в Access 2000, на основе этого поля получаются. Попробуйте не импортировать данные, а присоединить таблицу Access 97, и через запрос на добавление передать данные в Access 2000. Если это не помогает, то надо сбросить данные в промежуточный файл (другого формата) и затем загрузить их в базу данных.
Вопрос 109 (29.11.2000). Я использую ODE Tools Wizard для Access 97. При включении в состав приложения Run Time, Setup Wizard выдает сообщение "No current record.", потом пустое окно сообщения со знаком "!" и завершает работу. Чего хочет эта штука я самостоятельно разобраться не смог.
  1.Сожмите базу данных путем импорта объектов.
  2. Возможно в вашем проекте, есть связанные таблицы. Скопируйте весь проект в другой каталог, а старую папку обязательно переименуйте. Попробуйте открыть в новом каталоге таблицы, если одна из них не открывается, то исправьте ошибку.
Вопрос 111 (01.12.2000). Здравствуйте! У меня вопрос. Есть три поля в таблице "Долг", ''Тариф'', ''К оплате". Как сделать чтобы записи полей "Долг" и "Тариф" суммировались, а результат записывался в поле "К оплате"? Очень буду благодарен, если получу ответ!(и если можно please по проще).
   Купите любую книгу по Access и прочтите ВНИМАТЕЛЬНО информацию по запросам на обновление данных. Я думаю, что у Вас все получится.
Вопрос 112 (04.12.2000). Существует несколько одинаковых по структуре форм (журналов) A,B,C... каждый из которых основан на своей таблице Ta,Tb,Tc. Каждая из этих форм связана с формой D (на таблице Td) по полю KOD. По нажатию кнопки в любой из них - открывается форма D. Как создать процедуру, которая бы по двойному щелчку в форме D возвращала бы значение D.KOD именно в ту форму из которой была вызвана? Вариант, типа IsLoaded(<Имя формы>) применяющийся по-моему в "Борее", проверяющий какая форма загружена, применять не хотелось бы,т.к. при добавлении новых форм связанных с той же Td нужно будет всегда менять код в форме D, а это очень неудобно.
 Отвечает Дмитрий Чернов
Решение 1.
В формах Ta, Tb и Tc в процедуре открытия формы D пишется следующее
DoCmd.OpenForm "D", acNormal, , , acFormAdd, acWindowNormal, Me.name
Forms("D").SetCallFormName = Me.name
'В форме в заголовке модуля описываем переменную sFormName и процедуру общения с ней SetCallFormName.
Private sCallFormName As String
Public Property Let SetCallFormName(fName As String)
   sFormName = fName
End Property
Решение 2.
Хотя можно и просто (без Property Let)
Public sCallFormName As String
А далее в событии DblClick или любом другом обращаемся к форме следующим образом:
Forms(sCallFormName).элемент_управления.свойство
Forms(sCallFormName).свойство
и т.д. У меня к примеру это выглядело так
Private Sub Form_Close()
Dim ctrl As Control
  If Len(sFormName) > 0 Then
    If Len(sCtrlName) > 0 Then
       DoCmd.SelectObject acForm, sFormName
       Set ctrl = Forms(sFormName).Controls(sCtrlName)
       ctrl.Requery
       ctrl.Value = Me!code.Value
    End If
  End If
End Sub
Вопрос 113 (04.12.2000). Я недавно стала изучать Access. У меня к Вам просьба. Никак не могу описать правильно переменные, чтобы сосчитать массу 1 м2, например, ниже нормы. Если не трудно то откликнитесь.
  Ответ. Для расчета массы используется формула [Масса] = [Плотность] * [Объем]. Напишите законченное решение для этой задачи. Если все получится, то далее усложните ее и введите новые поля.
Вопрос 114 (05.12.2000). Как средствами Access( или Outlook, или ещё какими то премудростями) можно в автоматическом режиме отправлять сообщения по адресам
электронной почты, которые являются полями в таблице Access.
 Данный вопрос уже встречался, поэтому на него будет дан ответ в следующей подписке N20 и обязательно приведен пример в файле mdb.
Вопрос 115 (05.12.2000). Интересует мнение (совет, практическая помощь) по следующему вопросу. Имеются dbf файлы упакованные(arj или zip) с паролем, при распаковке возможно получение нескольких dbf файлов(таблицы, их структура частично сходна). Название файлов изменяется, но не полностью. В названии 7 символов(первые две буквы одинаковы для всех файлов).Каким образом их "автоматом" можно присоединять к таблице в Access, при этом нужно добавить недостающие поля и внести в них нужные значения. Очень срочно!!!
  Вопрос о динамическом подключении dbf файлов рассматривался. Смотрите пример 1 в файле la_table.mdb
Вопрос 117 (06.12.2000). Читая Вашу публикация наткнулся на фразу: "...Если по логике Вашей программы необходимо использовать какую-нибудь функцию несколькими пользователями, то ее записывают в DLL библиотеку ..." Сам я пока не высоко летаю. Объясните, пожалуйста, как можно свои функции загонять в DLL, и как ими пользоваться.
   1 этап. Для этого пишите функцию в Access, отлаживаете ее и сохраняете в файле с расширением *.bas. Смотрите пункт Export File...
   2 этап. Теперь открываете Visual Basic (отдельная программа), создаете новый проект (dll библиотеку) и добавляете свой код. После компиляции проекта получите dll файл.
   3 этап. Размещаете библиотеку в системной директории Windows, там где больше всего dll файлов.
   4 этап. В Access декларируете (описываете) функцию и далее обращаетесь, как с обычной функцией. Смотрите примеры по обращению с такими функциями в файлах: la_form.mdb (для api интерфейса). Пример по теме в формате mdb дам позже.
Вопрос 118 (07.12.2000). Не так давно подписался на Вашу рассылку Access 2000 - программирование... В связи с чем у меня возник вопрос. Предположим, что есть база содержащая две таблицы - Товар и Клиент. Таблицы связаны отношением один-ко- многим. Одному наименованию товара соответствует несколько клиентов, купивших его. Почему в окне Схема Данных, куда таблицы были добавлены и объединены связью, со временем ( в частности после создания запросов) появляется третья таблица ( дубликат таблицы Товар). Эта таблица также объедена связью. Никаких проблем в работу базы эта ситуация не вносит. Удаление таблицы-дубликата ничего не меняет. После закрытия Схемы Данных и открытия его вновь таблица-дубликат появляется опять. Я не занимаюсь Accessом профессионально, но все же хотелось бы знать почему происходит подобное, чем это вызвано.
   Возможно у Вас остались связи в базе данных. Сжатие системы не помогает. Попробуйте создать пустую базу данных и импортировать в нее все элементы старой. Структура новой базы будет лучше, чем новой. Если поможет, то сообщите ответ.
Вопрос 120 (07.12.2000). Нам очень понравилась Ваша программа "Курсы валют", написанная на Access 2000. Не могли бы Вы прислать нам эту программу в формате Access 1997? Будем Вам очень признательны.
   Нельзя. Так как при переводе из Access 2000 в Access 97 возникают проблемы, которые можно решить только имея достаточно много свободного времени.
Вопрос 121 (07.12.2000). Я недавно начал изучать Access2000. В одной таблице есть поле с датами. Мне необходимо, чтобы в другой таблице в одноименном поле была возможность выбрать одну из дат в раскрывающемся списке. В конструкторе в подстановках данного поля (типа Date) нет вставки. Как это осуществить?
   В данной ситуации могу только посоветовать использовать другой тип поля, например, числовое. Добавьте в свойства поля форматы для ввода и отображения по типу Date. После этого Вы сможете назначить ему список.
Вопрос 122 (07.12.2000). Мне необходима срочная консультация по Access. Сообщите, пожалуйста, номер телефона в Москве, кто бы мог помочь.
   Я не знаю, чтобы кто-то консультировал бесплатно по телефону. Тут надо в совершенстве знать саму базу данных и иметь много свободного времени. Обязательно опубликую телефоны, если кто-то откликнется. Сам я не обучаю таким образом, т.к. являюсь консультантом одной производственной и 2x торгово-посреднических организаций на платной основе. 
Вопрос 123 (08.12.2000). Установил SQL Server 7.0,  настроил источник данных ODBC,  подключил таблицу в Access. Права на изменение и добавление данных у меня есть. Данные без проблем добавляются с помощью Visual Basic 6.0, с помощью программульки Sqlw. С помощью Access-овских запросов SQL к серверу тоже могу добавлять данные. Но не могу ни добавить ни изменить данные непосредственно в таблице, только
просмотр (использую тоже самое подключение ODBC). Что делать? Ведь данные проще изменять в форме, основанной на подключенной таблице.
   Вообще при подключении к внешним таблицам используются внутренние Access и внешние ODBC драйверы. Я бы поэкспериментировал с внутренними драйверами, но для этого надо знать точно тип базы данных, хранящийся на сервере.
Вопрос 123а (13.12.2000). Не могу скачать Лекции Access 2000 1.0
Вышлите, пожалуйста. С наезжающим 21 веком (теперь уж точно)
  Спасибо за поздравление, но 21 века ждать не надо. 
Вопрос 124 (13.12.2000). Хочу я открыть файл .mdb в Access. и вижу сообщение: "у вас нет прав доступа". Читал вашу статью в которой есть ссылка http://www.leadersoft.ru/ , но туда попасть не могу. Подскажите, как мне открыть мой файл, или где бы взять описание .mdb файлов.
  Никакой защиты на файлах нет. Так, что у Вас проблемы с настройками Office. Если его установить по умолчанию и на локальный компьютер, то Все заработает. 
Вопрос 125 (13.12.2000). Я не программист, но по роду своей работы столкнулся с необходимостью создания баз данных для ведения расчётов результатов хозяйственной деятельности на своём предприятии. Понимая, что эта задача сама по себе далеко не проста, для начала хотел бы освоить азы программирования. Посоветуйте где в сети можно найти литературу отвечающую моему уровню и потребностям.
Вопрос 126 (13.12.2000). Не подскажите где можно найти учебник по Аксесу в электронном виде о том как писать модули, примеры простых программ на VBA. Заранее благодарен за любой ответ.
  Учебник по Access, который бы решил все Ваши вопросы, Вы не найдете. Серьезный учебник может занимать более 1000 страниц, и никакой автор на его публикацию в Интернете открытых кодов не пойдет. Добавить к сказанному можно то, что через раздел "Ресурсы Access" Вы сможете выйти на сайт, предлагающий компьютерную литературу и заказать учебник по почте.
Вопрос 127 (13.12.2000). Я живу в Узбекистане, где литературы по программированию практически нет. Работаю в Access уже около полутора лет, все обучение происходит методом проб и ошибок. Сейчас занимаюсь разработкой программы "Склад", и столкнулся с проблемой, необходимо в отчете за месяц выводить остатки товара на конец прошлого месяца, создавать отдельную таблицу для хранения остатков, пробовал, но совсем запутался в своих программах. Может есть какой-то другой путь. И кроме этого, необходимо в конце года архивировать данные за прошедший год, очищать базу, сохранять остатки с прошлого года, и начинать новый год. Здесь вообще не знаю как подступиться к этой проблеме.
  1. Остатки по складу лучше формировать не в таблице, а через запрос SQL. В этом запросе Вам надо связать таблицы по справочникам и документам по складу. Этот же запрос можно использовать и в отчете.
  2. Вторая проблема, которую Вы рассматриваете очень сложная. Идеального совета нет. Попробуйте сначала научиться создавать файлы mdb файлы (см. лекции), далее хорошо изучите запросы на обновление, удаление и добавление. Обязательно составьте схему связей таблиц. После этого уже переходите к решению самой задачи.
Вопрос 128 (13.12.2000). Куда Вы подевались - нет не рассылок, нет сайта? Укажите, пожалуйста, адреса, м. б. новые!!!
   Временно частота выпусков уменьшена до 2 в месяц из-за недостатка свободного времени. Перебои в работе сайта: www.leadersoft.ru в последнее время связаны с Новой почтой. Я обращался к ним по данному вопросу, но они ничего сделать не могут. У них постоянно возникают перегрузки сервера. Иногда бывает, что нет ftp-доступа, а в другой раз страницы не открываются. Сейчас анализируется информация по данной проблеме. Возможен переход к другому провайдеру, но тогда об этом будет сообщение.
Вопрос. Разработайте, пожалуйста, мне программу ...
   Уважаемые господа, предприниматели, бизнесмены и просто случайные люди, читающие данный тест. Мы предлагаем Вам бесплатные услуги, но не работаем на халяву. Если Вы думаете, что разработка Access базы данных - это легкий и примитивный труд, то Вы сильно заблуждаетесь. Информация дается очень сложно, и короткий, в 10 строчек код, может разрабатываться сколько угодно долго, часы, дни и даже месяцы.  Единственно, чем сразу можно Вам помочь, так это разместить информацию о проблеме в конференции: www.leadersoft.ru. Ответ на вопрос дается только по истечении некоторого периода времени. Но если Вам срочно нужна новая программа, подробный ответ с написанием кода, то пишите разработчикам (смотрите Визитки), а также можете взять почтовые адреса из ответов в подписке. Могу гарантировать, что к Вам будут относиться более серьезно, если Вы напишите примерное письмо: "Уважаемый господин (...печатаете инициалы) Я посмотрел Вашу визитку (или решение). Предлагаемые Вами способы решения задач по Access,  мне понравились. Прошу дать ответ на следующий вопрос. У меня есть проблема, которая требует срочного разрешения (...даете полное описание) Если сможете, то решите ее, готов оплатить все расходы за консультацию и разработку программы. С уважением, (... печатаете имя, организацию и желательно должность)"

 

Выпуск 32. Защита данных алгоритмом RSA

 Услуги по разработке. Если база Вам нужна, в LeaderSoft зайди сперва.
      Мы разрабатываем по заказам клиентов различные программы, используя Microsoft Access. Базы данных разрабатываются "с нуля" или, используя готовые решения, что позволяет достаточно гибко решать финансовые вопросы по оплате услуг за разработку.       Имеется следующий опыт внедрения программ:
 • Бухгалтерских , смотрите описание программ Склад и Реализация, Касса предприятия, Банк предприятия, Книги продаж и покупок
• Табличных , т.е. программ перевода финансового или складского учета из Excel или FoxPro в Access
 • Совместных , т.е. когда будет сделана только часть программы, например, меню, форма, отчет или модуль VBA, а остальная доработка будет выполнена вами.
 • Конвертеров , т.е. программ загрузки текстовых файлов *.ini, *.txt или табличных баз данных *.dbf, *.db в Access без использования внешних драйверов.
 • Реанимационных , т.е. доработка некачественно созданных или неустойчиво работающих в сети баз данных.
      Форма сотрудничества - любая, т.е. возможно заключение договора на разработку как с организацией, так и с одним или группой программистов. 
      Срок разработки: от 2 дней до 2 месяцев

 Программа "Склад и Реализация" в открытом формате
Программа "Склад и Реализация" поставляется теперь в полностью открытом формате. Разработка имеет удобный интерфейс, много отличных решений, отлаживалась несколько лет. Программа поставляется в виде:
• бесплатной ознакомительной инструкции- брошюры.
• рабочей версии с программой инсталляции
• версии с открытым программным кодом файл, включая все mdb файлы (Цена: договорная)

 Новости сайта
23.10.2001. На этой странице указаны специальные программы, которые Вы можете получить путем обмена на отчет, форму или оригинальный пример базы данных. Если у Вас нет возможности найти программу для обмена, то Вы можете купить ее. Условия продажи смотрите по верхней ссылке.
 Код  Файл    Примеры Описание
0001 profi_prot1.zip   Подбор ключей для шифрования RSA   11 пример файла profi_prot.zip. Подбор ключей для шифрования данных открытым ключем RSA, т.е. когда для шифрования данных используется открытый ключ, а для расшифровки закрытый. Применение - защита полей базы данных.
      Управление реестром Windows   12 пример файла profi_prot.zip. Пример показывает как можно из базы данных управлять реестром  Windows. Рассматриваются функции удаления и сохранения ключей реестра. Применение - защита базы данных, сохранение в реестре настроек базы и т.п.
0002 profi_perl.zip Управление Access из Perl   1 пример. Файлы архива: readme.htm, test.mdb, msaccess.pl, httpd.conf, host, dbi-odbs.txt. Данный пример будет полезен прежде всего тем, кто работает с Microsoft Access в Интернете, иcпользуя скрипты Perl в операционных системах NT, Unix под управлением сервера Apache.
0003 profi_valuta.zip  Курсы валют   Курсы валют Центрального банка России, начиная с 01 июля 1992 года. Все данные проверены и соответствуют базе данных ЦБ.


 22.10.2001. Добавились 3 новых примера по работе с файловой системой. Смотрите la_files.mdb.
  • 1 пример показывает как найти все файлы в папке с использованием подкаталогов и маски для поиска (Application.FileSearch);
Следующие примеры показывают как лучше
  • 2 пример показывает как создать, скопировать, переместить и удалить папку с использованием FileSystemObject. Рассматриваются свойства: fs.CreateFolder, fs.DeleteFolder, fs.MoveFolder, fs.CopyFolder
  • 3 пример показывает как получить свойства папки и ее объектов с использованием FileSystemObject свойства files, drive и т.п.


  Защита базы данных открытым ключом RSA
    В этой рассылке рассказывается об одном из наиболее популярных методов защиты базы данных открытым ключом RSA, названый так по начальным буквам фамилий ее изобретателей (Rivest, Shamir and Adleman). Возникает вопрос, а надо ли еще "городить" новый вариант защиты, когда уже есть встроенные системы защиты в Access, такие как, ограничение доступа к объектам базы данных на основе пароля или системного файла system.mdw.
   Ответ однозначный - необходимо, т.к. из-за высокой популярности использования Access файлов, все больше специалистов пытаются определить структуру mdb файла (см. AccessRecovery или la_prot.mdb). Cледовательно нет 100% уверенности, что не появится программа, которая прочитает ваши данные. Таким образом, попробуем разобраться в алгоритме RSA, чтобы потом применить его к защите полей вашей базы данных.
   В RSA используется для шифрования один ключ, а для расшифровки другой. Первый ключ не является секретным и может быть известен всем, кто работает с базой данных. 
 
Очевидные факторы алгоритма :
  • расшифровать данные с помощью известного ключа невозможно;
  • ключ расшифровки не может быть определен из ключа шифрования;
  • ключи должны иметь очень большую величину;
 
Определим термины, которые встречаются при описании алгоритма:
 • простое число - это такое, которое может делится только на 1 и на само себя;
 • взаимно простые числа - это числа не имеющие ни одного общего делителя кроме 1;
 • i mod j - деление по модулю;
 • i ^ j - возведение в степень j числа i;
 
Описание алгоритма RSA. В скобках дан пример вычислений в цифрах.
1. Возьмем два простых числа A и B. [3 и 11]
2. Определим c=A*B
[33]
3. Выберем число d
[3] взаимно простое с выражением (A-1)*(B-1) [20]
4. Найдем число e
[7], чтобы (e*d) mod ((A-1)*(B-1))=1
5. Итак,
 
e[7] и c[33] - открытый ключ
 
d[3] и c[33] - секретный ключ
Проверка алгоритма
6. Зашифруем число x
[2] по формуле: p=(x^e) mod c [((2^7) mod 33)=29]
7. Расшифруем число p[29] по формуле: x=(p^d) mod c [((29^3) mod 33)=2]
 
Выводы
  1. Перед шифрованием надо разбить текст на блоки, а затем каждому из них дать определенное число. В примере выше использован простой случай, т.е. текст разбивается на символы, где число x  имеет код 2.
  2. Сам процесс зашифровки/расшифровки требует эффектных решений, т.к. если использовать стандартные математические операции для расчета, то уже для простых чисел 23 и 17 может возникнуть переполнение при возведении в степень. Как этого избежать и подобрать простые числа указано в файле: profi_prot1.mdb
  3. Для проверки изложенного выше алгоритма используйте следующую программу (действует на малых числах):
 
Тестирование
   Private Sub funTestRSAencryption()
Dim A As Long, B As Long, c As Long
Dim d As Long, e As Long, x As Long, p As Long
'1. Возьмем два простых числа A и B.
A = 3
B = 11
Debug.Print "A=" & A, "B=" & B
'2. Определим c = A * B
c = A * B
Debug.Print "C=" & c
'3. Выберем число d взаимно простое с выражением (A-1)*(B-1)
d = 3
Debug.Print "Test1=" & (A - 1) * (B - 1)
'4. Найдем число e, чтобы (e*d) mod ((A-1)*(B-1))=1
e = 7
Debug.Print "Test2=" & (e * d) Mod ((A - 1) * (B - 1))
'5. Выбираем символ x для шифрования
x = 2
Debug.Print "X=" & x
'6. Зашифруем число x по формуле: p=(x^e) mod c
p = x ^ e Mod c
Debug.Print "P=" & p
'7. Расшифруем число p по формуле: x=(p^d) mod c
x = (p ^ d) Mod c
Debug.Print "X=" & x
   End Sub

   P.S. В качестве дополнительного материала, я бы посоветовал прочитать книгу "Защита информации в персональных ЭВМ", Спесивцев, Вегнер, Крутяков, Серегин, Сидоров. Москва "РАДИО и СВЯЗЬ" 1992 год, стр. 39-41. Вот умная выдержка из этой книги
   Криптостойкость алгоритма RSA основывается на предположении, что исключительно трудно определить секретный ключ по известному, поскольку для этого необходимо решить задачу о существование делителей целого числа. Данная задача является NP – полной и, как следствие этого факта, не допускает в настоящие время эффектного (полиномиального) решения. Более того, сам вопрос существования эффективных алгоритмов решения NP – полных задач является до настоящего времени открытым. В связи с этим для чисел, состоящих из 200 цифр (а именно такие числа рекомендуются использовать), традиционные методы требуют выполнения огромного числа операций (около 10^23).

Ответы на вопросы


Вопрос. Можно ли использовать базу данных Microsoft Access на web сайте, где установлен Unix или Lunix?
Ответ.
Можно и нужно. Я думаю, что здесь есть несколько причин которые могут заинтересовать пользователей:
  • Unix более надежная операционная система, т.к. проблемы совместного доступа к файлам решены лучше, чем в Windows
  • Цена Unix хостинга примерно в два ниже, чем NT. Потратив всего 7-8 $ в месяц, Вы сможете не только открыть свой сайт, но и использовать на нем скрипты. Под ними понимается возможность создания динамических страниц, конференций, голосований с применением  баз данных на сайте.
  • ~70 web серверов работают под управлением операционной cистемы Unix, следовательно у Вас не будет больших проблем с поиском провайдера
  • В OS Unix (код открыт) используется  web сервер Apache (код открыт) и язык Perl с библиотеками (код открыт). Все это приводит к тому, что можно свободно вносить свои изменения в работу многих программ.
  • Использование Access в качестве базы данных лучше, чем mySQL, т.к. структура ее лучше.
 
С чего начать?
Начните установку программ у себя в Windows (см. ссылки синим цветом), а потом перенесите свой опыт на сервер провайдера. Выполнить надо всего 5 шагов.
 1. Установите у себя сервер Apache.
 2. Установите ActivePerl
 3. Установите модуль DBI
 4. Установите DBD::ODBC
 5. Протестируйте программу работы с базой данных.
 
Как установить сервер Apache?
Сервер Apache работает под управлением операционной системы Windows и Unix. Распространяется в открытых кодах, поддерживается независимыми разработчиками и поэтому полностью бесплатен. Инструкция по установке в Windows достаточно простая, но требует ручного вмешательства.
1. Скачайте сервер (ссылка вверху или купите книгу с CD-диском, например, Клинтон Пирс "Освой самостоятельно Perl").
2. Установку проведите в папку: с:\usr\local\apache
3. Отредактируйте файл: с:\usr\local\apache\conf\httpd.conf
  
Как установить ActivePerl?
Установку проведите в папку: с:\usr , чтобы использовать стандартный оператор #!usr/bin/perl в большинстве скриптов *.pl 
  
Что такое DBI?
 DBI - Database Interface. DBI представляет собой набор методов, переменных для обеспечения взаимодействия сценария Perl c базой данных. Самое оптимальное для поиска модуля использовать команду: ppm search. Она работает в том случае, если Вы подключены к Интернету. Установку проведите командой ppm install dbi
 
Что такое DBD::ODBC?
 DBD - Database Driver. DBD - программный драйвер для связи с конкретной базой данных. Например, для работы  с Access в Win 32 загрузите DBD-ODBC.zip. Для Linux/Unix Вам придется поискать их. Название файлов могут быть такими freeODBC, unixODBC or iODBC. Установку проведите командой ppm install dbd-odbc
 
Как протестировать базу данных?
1. Тестирование наличия модулей DBI и ODBC в Win32 можно проверить командой info в ppm. Например, PPM> info dbi и PPM> info dbd-odbc. Если модули установлены, то команда отобразит номер соответствующей версии.
 
2. Для тестирования базы данных в Internet браузере наберите в текстовом редакторе пример:
#!usr/bin/perl
use DBI;
$dbh = DBI->connect("dbi:ODBC:'driver=Microsoft Access Driver (*.mdb);dbq=test.mdb'",'','');
$dbh->disconnect;

3. Проверьте файл: error.log. Если, что-то сделано неправильно, то в файле Вы прочитаете сообщение об ошибке.
 
 Дополнение
Более подробно об этой информации изложено в архиве: profi_perl.zip. Он включает несколько файлов. Readme.htm - общая информация, test.mdb - пример базы данных, msaccess.pl - пример на языке perl c построением таблицы базы данных, httpd.conf - конфигурация сервера apache, host - файл настройки IP адреса, dbi-odbs.txt - список файлов DBI и ODBC, устанавливаемых на сервере.