(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Экспорт отчетов в HTML

Источник: msadimsign

MS Access 2000, под которым я сейчас сижу -- достойный памятник тех времён, когда один известный человек думал, что Интернет "малоперспективен".
 
Через то самое место, которым он в этот момент думал, в MS Access 2000 сделаны и экспорт в HTML, и возможность отправки отчёта по емейлу.

Пока в моей программе отчёт, который нужно было посылать по емйлу, был один - я писал программульку 'конвертации индивидуально для него.
Но покупатели оценили возможность отправки отчёта по емейлу - причём в теле письма. Число отчётов теперь с катастрофической скоростью растёт - и приходится придумывать что-то хоть немного уиверсальное.

Причём крайне важно придумать что-то такое, чтоб чутко реагировало на зменения МАКЕТА отчётов.
Поддерживать-то программу надо... И кое-что я придумал. Может, это поможет и Вам.

Attribute VB_Name = "export_to_HTML"
Option Compare Database
Option Explicit
Public subreportHTML As String

' 1. Как нам обустроить экспорт
'---------------------------------
'У отчёта в Аксессе есть следующие области: заголовок, верхний колонтитул, данные, нижний колонтитул, примечание
'У всех у них сть событие "Форматирование" (Format). Именно на него имеет смысл вешать программу, преобразующую содержание
'области в HTML-код

'Все эти программы могут дописывать один и тот же файл.
'(Если Вы считаете, что умнее собирать код в переменную String -- я соглашусь, но напомню,
'что ЗДЕСЬ ВАМ НЕ ТУТ: в MS Access стринг-переменная в один не самый лучший момент просто перестаёт удлиняться, ничего не сообщая системе и Вашей программе)

'Итак, для областей отчёта нужна функция, пробегающая контролы и сохраняющая их содержание и оформление в HTML

'Напишем функцию section_to_HTML(), которая это сделает. Она преобразует секцию в DIV
'с абсолютной позицией, и внутри него спозиционирует все контролы

'В Аксессе есть полезные констаты для обозначения типов контрола:

'acBoundObjectFrame Присоединённая рамка объекта
'acCheckBox         Флажок
'acComboBox         Комбобокс (выпадающий список)
'acCommandButton    Кнопка
'acCustomControl    ActiveX (custom) control
'acImage            Картинка
'acLabel            надпись
'acLine             линия
'acListBox          список
'acObjectFrame      свободная рамка объекта
'acOptionButton     переключатель (Радиокнопка)
'acOptionGroup      группа элементов управления
'acPage             Page
'acPageBreak        Page break
'acRectangle        Прямоугольник
'acSubform          подчинённая форма/отчёт
'acTabCtl           Набор вкладок
'acTextBox          текстовое поле
'acToggleButton     переключатель ("залипающая" кнопка)

'2. Так начнём же функцию сию...
'----------------------------------

Function section_to_HTML(ByRef our_section As Section, ByVal n As Integer, ByVal top As Long, Optional ByRef output As String) As Long
'our_section -- заголовок или примечание
'n   -- дескриптор файла, в который пишем
'       Если равен нулю -- никуда не пишем
'top -- сколько отступить от начала страницы в твип (1мм=56.7 твип)
'       Эту величину придётся высчитывать в процессе формирования файла
'output --  В эту переменную собирается весь HTML-код секции
'           Рекомендуется использовать только для совсем маленьких секций:
'           переменная типа String вопреки документации может "переполниться"

On Error GoTo oblom

Dim html As String

html = vbCrLf & "<div style=""position:absolute;width:"
html = html & Int(our_section.Parent.width / 56.7) 'ширина отчёта в мм
html = html & "mm;height:" & Str(round(our_section.Height, 2)) & "mm"
html = html & ";top:" & top & "mm"
html = html & ";background-color:" & toRGB(our_section.BackColor)
html = html & """>" & vbCrLf

output = output & html
If (n <> 0) Then Print #n, html

'теперь пробегаем контролы
'Отсортируем их по возрастанию свойства TOP, а затем LEFT
'(сверху вниз и слева направо)
'Для этого загоним их в таблицу (чтоб с  массивами не бороться)

'Проверим, есть ли таблица tmpControls
Dim t As Dao.TableDef
Dim exists As Boolean
exists = False
For Each t In CurrentDb.TableDefs
    If t.Name = "tmpControls" Then
        exists = True
        Exit For
    End If
Next t

If exists Then 'Есть таблица
    CurrentDb.Execute ("delete from tmpControls")
Else 'Нет таблицы tmpControls. Сейчас будет
    
    Dim tbl As Dao.TableDef

    Set tbl = CurrentDb.CreateTableDef("tmpControls")
    
    With tbl
        .Fields.Append .CreateField("top_", dbLong) 'Чтоб отсортировать по отступу от верха
        .Fields.Append .CreateField("left_", dbLong) 'Чтоб отсортировать по отступу слева
        .Fields.Append .CreateField("controlName", dbText)
    End With
    
    CurrentDb.TableDefs.Append tbl
    CurrentDb.TableDefs.Refresh
End If

'Итак,таблица tmpControls с двумя полями у нас есть (в конце функции мы её... того..)
'заполним таблицу

Dim ctrl As Control
Dim p As Property
Dim query As String

For Each ctrl In our_section.Controls
    If (ctrl.Properties("Visible") = True) Then
        query = "insert into tmpControls (top_,left_,controlName)"
        query = query & " values (" & ctrl.Properties("Top") & "," & ctrl.Properties("Left") & ",'" & ctrl.Properties("Name") & "')"
        CurrentDb.Execute (query)
    End If
Next ctrl

Set ctrl = Nothing

'Итак,таблица tmpControls заполнена
'Пройдём по её записям

Dim rst As Dao.Recordset
Dim idx As String
Dim deltaTOP As Long
deltaTOP = 0

Set rst = CurrentDb.OpenRecordset("select * from tmpControls order by  top_,left_")
Do While Not rst.EOF
        idx = rst!ControlName
        Set ctrl = our_section.Parent.Controls(idx) 'Приходится "через верх" обращаться...
        Select Case ctrl.Properties("ControlType")
            Case acTextBox
                html = text_Box(ctrl, deltaTOP)
            Case acLabel
                html = label_Box(ctrl, deltaTOP)
            Case acComboBox
                html = combo_Box(ctrl, deltaTOP)
            Case acImage
                html = image_Box(ctrl, deltaTOP)
            Case acSubform
                html = subform_BOX(ctrl, deltaTOP)
            Case acLine
                html = line_BOX(ctrl, deltaTOP)
            Case acRectangle
                html = rect_BOX(ctrl, deltaTOP)
            
        
            Case Else
                'Признаться, мне просто пока незачем обрабатывать
                'остальные виды контролов
                'Если Вы испоьзуете что-то кроме перечисленного --
                'Вам придётся попрограммировать, взяв за основу
                'text_Box() и др.
                html = ""
        End Select
        output = output & html
        If (n <> 0) Then Print #n, html
        rst.MoveNext
Loop

rst.Close

'Прибьем таблицу
CurrentDb.TableDefs.Delete ("tmpControls")
        
'закроем ДИВ
html = vbCrLf & "</div>" & vbCrLf
output = output & html
If (n <> 0) Then Print #n, html

section_to_HTML = our_section.Properties("Height") / 56.7 + deltaTOP + 2
Exit Function
oblom:
section_to_HTML = False

End Function

'-----------------------------
'Ну а теперь -- вспомогательные функции
'-----------------------------

'перевод цвета в формате Access в RGB
Function toRGB(ByVal color As Long) As String
Dim r As Long
Dim g As Long
Dim b As Long

b = color \ 256 \ 256
g = (color - b * 256 * 256) \ 256
r = color - b * 256 * 256 - g * 256

toRGB = "#"

If (Len(Hex(r)) = 1) Then toRGB = toRGB & "0"
toRGB = toRGB & Hex(r)
If (Len(Hex(g)) = 1) Then toRGB = toRGB & "0"
toRGB = toRGB & Hex(g)
If (Len(Hex(b)) = 1) Then toRGB = toRGB & "0"
toRGB = toRGB & Hex(b)

End Function

Function text_Box(ctrl As Control, ByRef deltaTOP As Long) As String
On Error GoTo oblom
Dim html As String
html = vbCrLf & "<div style=""position:absolute;top:"
html = html & Str(round(((ctrl.Properties("Top") / 56.7) + deltaTOP), 2))
html = html & "mm;left:"
html = html & Str(round(ctrl.Properties("Left") / 56.7, 2))
html = html & "mm"
html = html & ";font-size:" & ctrl.Properties("FontSize") & "pt"
html = html & ";font-family:" & ctrl.Properties("FontName")
html = html & ";color:" & toRGB(ctrl.Properties("ForeColor"))

If (ctrl.Properties("BackStyle") = 1) Then 'Тип фона -- обычный
    html = html & ";background-color:" & toRGB(ctrl.Properties("BackColor"))
End If

html = html & ";text-align:"

Select Case (ctrl.Properties("TextAlign"))
    Case 0, 1
        html = html & "left"
    Case 2
        html = html & "center"
    Case 3
        html = html & "right"
End Select

'Есть ли граница?
html = html & ";border:"
If (ctrl.Properties("BorderStyle") = 0) Then
        html = html & "none"
Else
    html = html & ctrl.Properties("BorderWidth") & "px solid "
    html = html & toRGB(ctrl.Properties("BorderColor "))
    html = html & ";padding:2px"
End If

html = html & ";width:" & Int(ctrl.Properties("Width") / 56.7) & "mm"
If (ctrl.Properties("FontItalic") = True) Then
    html = html & ";font-style:italic"
End If

If (ctrl.Properties("FontWeight") >= 600) Then
    html = html & ";font-weight:bold"
End If

If (ctrl.Properties("FontUnderline") = True) Then
    html = html & ";text-decoration:underline"
End If

'А теперь проверим: не расширилось ли поле
If ctrl.Properties("CanGrow") Then 'Если поле может расширяться
    'Прикинем (грубо!), насколько поле расширилось
    'используемые функции можно со временем улучшать
    Dim w, h As Integer
    w = charWidth(ctrl)     'Ширина символа
    h = charHeight(ctrl)    'Высота символа
    
    'Сколько строк будет в "штатном" размере?
    Dim rows_plan As Integer
    rows_plan = Int(ctrl.Properties("Height") / 56.7 / h) + 1
    'Debug.Print "rows_plan=" & rows_plan
    
    'Сколько строк будет реально? Можем только гадать:
    Dim rows_real As Integer
    rows_real = Len(ctrl.Properties("Text")) / (Int(ctrl.Properties("Width") / 56.7 / w) - 3) + 1
    'Debug.Print "Len(ctrl.Properties(""Text""))=" & Len(ctrl.Properties("Text")) & ", w=" & w & ", rows_real=" & rows_real
    'зададим смещение
    deltaTOP = deltaTOP + Max((rows_real - rows_plan) * h, 1)
End If

html = html & ";height:" & Int(ctrl.Properties("Height") / 56.7) + deltaTOP & "mm"
html = html & """>"
html = html & replace(ctrl.Properties("Text"), vbCrLf, "<br />")
html = html & "</div>"

text_Box = html

Exit Function
oblom:
Resume Next
End Function
'Опрделяем высоту символа в мм по размеру кегля (как умеем :( )
Function charHeight(ctrl As Control) As Integer
charHeight = Int(ctrl.Properties("FontSize") / 2.5)
End Function
'Опрделяем ширину символа в мм по размеру кегля (как умеем :( )
Function charWidth(ctrl As Control) As Integer
charWidth = Int(ctrl.Properties("FontSize") / 3)
End Function

Function label_Box(ctrl As Control, ByRef deltaTOP As Long) As String
On Error GoTo oblom
Dim html As String
html = vbCrLf & "<div style=""position:absolute;top:"
html = html & Str(round((ctrl.Properties("Top") / 56.7) + deltaTOP, 2))

html = html & "mm;left:"
html = html & Str(round(ctrl.Properties("Left") / 56.7, 2))
html = html & "mm"
html = html & ";font-size:" & ctrl.Properties("FontSize") & "pt"
html = html & ";font-family:" & ctrl.Properties("FontName")
html = html & ";color:" & toRGB(ctrl.Properties("ForeColor"))

If (ctrl.Properties("BackStyle") = 1) Then 'Тип фона -- обычный
    html = html & ";background-color:" & toRGB(ctrl.Properties("BackColor"))
End If

html = html & ";text-align:"

Select Case (ctrl.Properties("TextAlign"))
    Case 0, 1
        html = html & "left"
    Case 2
        html = html & "center"
    Case 3
        html = html & "right"

End Select

'Есть ли граница?
html = html & ";border:"
If (ctrl.Properties("BorderStyle") = 0) Then
        html = html & "none"
Else
    html = html & ctrl.Properties("BorderWidth") & "px solid "
    html = html & toRGB(ctrl.Properties("BorderColor "))
    html = html & ";padding:2px"
End If

html = html & ";width:" & Int(ctrl.Properties("Width") / 56.7) & "mm"
If (ctrl.Properties("FontItalic") = True) Then
    html = html & ";font-style:italic"
End If

If (ctrl.Properties("FontWeight") >= 600) Then
    html = html & ";font-weight:bold"
End If
If (ctrl.Properties("FontUnderline") = True) Then
    html = html & ";text-decoration:underline"
End If

html = html & ";height:" & Int(ctrl.Properties("Height") / 56.7) & "mm"
html = html & """>"
html = html & replace(ctrl.Properties("Caption"), vbCrLf, "<br />")

html = html & "</div>"

label_Box = html

Exit Function
oblom:
Resume Next
End Function
Function combo_Box(ctrl As Control, ByRef deltaTOP As Long) As String
On Error GoTo oblom
Dim html As String
html = vbCrLf & "<div style=""position:absolute;top:"
html = html & Str(round(((ctrl.Properties("Top") / 56.7) + deltaTOP), 2))
html = html & "mm;left:"
html = html & Str(round(ctrl.Properties("Left") / 56.7, 2))
html = html & "mm"
html = html & ";font-size:" & ctrl.Properties("FontSize") & "pt"
html = html & ";font-family:" & ctrl.Properties("FontName")
html = html & ";color:" & toRGB(ctrl.Properties("ForeColor"))

If (ctrl.Properties("BackStyle") = 1) Then 'Тип фона -- обычный
    html = html & ";background-color:" & toRGB(ctrl.Properties("BackColor"))
End If

html = html & ";text-align:"

Select Case (ctrl.Properties("TextAlign"))
    Case 0, 1
        html = html & "left"
    Case 2
        html = html & "center"
    Case 3
        html = html & "right"

End Select

'Есть ли граница?
html = html & ";border:"
If (ctrl.Properties("BorderStyle") = 0) Then
        html = html & "none"
Else
    html = html & ctrl.Properties("BorderWidth") & "px solid "
    html = html & toRGB(ctrl.Properties("BorderColor "))
End If

html = html & ";width:" & Int(ctrl.Properties("Width") / 56.7) & "mm"
If (ctrl.Properties("FontItalic") = True) Then
    html = html & ";font-style:italic"
End If

If (ctrl.Properties("FontWeight") >= 600) Then
    html = html & ";font-weight:bold"
End If
If (ctrl.Properties("FontUnderline") = True) Then
    html = html & ";text-decoration:underline"
End If

html = html & ";height:" & Int(ctrl.Properties("Height") / 56.7) & "mm"
html = html & """>"

'Узнаём, что выбрано в поле
'Для этого посмотрим, сколько колонок в списке и ширина каких из них не равна нулю
Dim cols As Integer
cols = ctrl.Properties("ColumnCount")
Dim i As Integer
Dim txt, ColumnWidths, token As String
txt = ""
ColumnWidths = ctrl.Properties("ColumnWidths")
    'Debug.Print " * * * "
For i = 0 To (cols - 1)
    'Debug.Print ColumnWidths
    If (InStr(1, ColumnWidths, ";") <> 0) Then
        token = Trim(left(ColumnWidths, InStr(1, ColumnWidths, ";") - 1))
    Else
        token = ColumnWidths
    End If
    'Debug.Print token
    If (token <> "0") Then
        txt = ctrl.column(i, ctrl.Properties("ListIndex"))
        Exit For
    End If
    ColumnWidths = Mid(ColumnWidths, InStr(1, ColumnWidths, ";") + 1)
    'Debug.Print ColumnWidths
Next i
    'Debug.Print " * * * "

html = html & txt
html = html & "</div>"

combo_Box = html

Exit Function
oblom:
Resume Next
End Function
Function image_Box(ctrl As Control, ByRef deltaTOP As Long) As String
On Error GoTo oblom
Dim html As String
html = vbCrLf & "<div style=""position:absolute;top:"
html = html & Int(ctrl.Properties("Top") / 56.7) + deltaTOP
html = html & "mm;left:"
html = html & Int(ctrl.Properties("Left") / 56.7)
html = html & "mm"

'Есть ли граница?
html = html & ";border:"
If (ctrl.Properties("BorderStyle") = 0) Then
        html = html & "none"
Else
    html = html & ctrl.Properties("BorderWidth") & "px solid black"
End If

html = html & ";width:" & Int(ctrl.Properties("Width") / 56.7) & "mm"
html = html & ";height:" & Int(ctrl.Properties("Height") / 56.7) & "mm"

html = html & ";height:" & Int(ctrl.Properties("Height") / 56.7) & "mm"
html = html & """>"

'А теперь, собственно, картинка

html = html & vbCrLf & "<img src="""

Dim fs As Object
Set fs = CreateObject("Scripting.FileSystemObject")
html = html & fs.GetFileName(ctrl.Picture)
html = html & """"

html = html & " style="""
html = html & "width:" & Int(ctrl.Properties("Width") / 56.7) & "mm"
html = html & ";height:" & Int(ctrl.Properties("Height") / 56.7) & "mm"
html = html & """"

html = html & ">"
html = html & "</div>"

image_Box = html

Exit Function
oblom:
Resume Next
End Function

Function subform_BOX(ctrl As Control, ByRef deltaTOP As Long) As String
'Мои подчинённые отчёты уже знают, что они будут подчинёнными
'Поэтому они на открытие помещают свой ХТМЛ-код в глобальную переменную subreportHTML,
'Для чего можно использовать section_to_html без записи в файл, например:
'    subreportHTML = ""
'    Call section_to_HTML(DataField, 0, 0, subreportHTML)
'Где DataField -- присвоенное мной имя области данных (если подчинённый отчёт состоит только из неё)

On Error GoTo oblom
Dim html As String
html = vbCrLf & "<div style=""position:absolute;top:"
html = html & Int(ctrl.Properties("Top") / 56.7) + deltaTOP
html = html & "mm;left:"
html = html & Int(ctrl.Properties("Left") / 56.7)
html = html & "mm"

'Есть ли граница?
html = html & ";border:"
If (ctrl.Properties("BorderStyle") = 0) Then
        html = html & "none"
Else
    html = html & ctrl.Properties("BorderWidth") & "px solid black"
End If
html = html & """>"
html = html & subreportHTML

html = html & "</div>"

subform_BOX = html

Exit Function
oblom:
Resume Next
End Function

Function line_BOX(ctrl As Control, ByRef deltaTOP As Long) As String

On Error GoTo oblom
Dim html As String
html = vbCrLf & "<div style=""position:absolute;top:"
html = html & Int(ctrl.Properties("Top") / 56.7) + deltaTOP
html = html & "mm;left:"
html = html & Int(ctrl.Properties("Left") / 56.7)
html = html & "mm"

If (Int(ctrl.Properties("Width")) = 0) Then
    html = html & ";width:"
    html = html & ctrl.Properties("BorderWidth") + 1
    html = html & "mm"
    html = html & ";height:"
    html = html & Str(round((ctrl.Properties("Height") / 56.7), 2))
    html = html & "mm"
    html = html & ";border-left:" & ctrl.Properties("BorderWidth") & "px solid "
    html = html & toRGB(ctrl.Properties("BorderColor"))
ElseIf (Int(ctrl.Properties("Height")) = 0) Then
    html = html & ";width:"
    html = html & Str(round((ctrl.Properties("Width") / 56.7), 2))
    html = html & "mm"
    html = html & ";height:"
    html = html & ctrl.Properties("BorderWidth") + 1
    html = html & "mm"
    html = html & ";border-top:" & ctrl.Properties("BorderWidth") & "px solid "
    html = html & toRGB(ctrl.Properties("BorderColor"))
Else
    'Надеюсь не увидеть в своих отчётах косые линии
    'Увижу -- буду гиф вставлять :(
End If

html = html & """></div>"

line_BOX = html

Exit Function
oblom:
Resume Next
End Function

Function rect_BOX(ctrl As Control, ByRef deltaTOP As Long) As String

On Error GoTo oblom
Dim html As String
html = vbCrLf & "<div style=""position:absolute;top:"
html = html & Int(ctrl.Properties("Top") / 56.7) + deltaTOP
html = html & "mm;left:"
html = html & Int(ctrl.Properties("Left") / 56.7)
html = html & "mm"

html = html & ";width:"
html = html & Str(round((ctrl.Properties("Width") / 56.7), 2))
html = html & "mm"

html = html & ";height:"
html = html & Str(round((ctrl.Properties("Height") / 56.7), 2))
html = html & "mm"

html = html & ";border:" & ctrl.Properties("BorderWidth") & "px solid "
html = html & toRGB(ctrl.Properties("BorderColor"))

If (ctrl.Properties("BackStyle") = 1) Then 'Тип фона -- обычный
    html = html & ";background-color:" & toRGB(ctrl.Properties("BackColor"))
End If

html = html & """></div>"

rect_BOX = html

Exit Function
oblom:
Resume Next
End Function

'---------------------------
'3. Как это всё использовать
'---------------------------

'Думаю,  к концу этого эссе Вы уже забыли, с чего мы начали :)

'Напомню: мы хотели отчёт в HTML перегнать

' -= Делай-раз =-.
'В модуле отчёта, который хотим экспортнуть в HTML, длаем две глобальные переменные --
'1. дескриптор файла
'2. Отступ следующго ДИВа.

'Например:
'Dim n As Long
'Dim nextTOP As Long
'
' -= Делай-два =-.
'На событие ОТКРЫТИЕ отчёта, который хотим экспортнуть в HTML,
'Вешаем что-то вроде

'n = FreeFile
'Open "c:\test.html" For Output As #n
'Print #n, "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">"
'Print #n, "<html><head></head><body>"
'nextTOP=0

' -= Делай-три =-.
'На событие ФОРМАТИРОВАНИЕ всех областей отчёта вешаете
'nextTOP = nextTOP+section_to_HTML(reportTitle, n, nextTOP)

' -= Делай-четыре =-.

'Событие ФОРМАТИРОВАНИЕ примечания отчёта закончите так:
'Print #n, "</body></html>"
'Close #n

'---------------------------
'4. Ну и что в итоге?
'---------------------------

'В итоге получается файл на диске, содержащий HTML-код отчёта. Проблем аж две:

'1. Подогнанные вплотную элементы отчёта в HTML иногда разделяются маленькими,
'   но заметными щелями. ЛЕЧИТСЯ корректировкой макета -- небольшим (не более 0.5 мм) "наезжанием"
'   правой области  на левую (затем левую область нужно вынести на первый план)
'2. Случается, что ДИВы разных областей отчёта немного налезают друг на друга.
'   ЛЕЧИТСЯ корректировкой третьего параметра функции section_to_HTML для нижней области,
'   отвечающего за отступ области от верхнего края

'Все проблемы лечатся в худшем случае несколькими минутами работы с HTML-кодом.

'Но зато получившийся результат можно быстро и легко послать по e-mail.
'Или подготовить HTML-страничку для выкладывания на сайт
 

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 19.02.2008 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Microsoft Office 365 Профессиональный Плюс. Подписка на 1 рабочее место на 1 год
Microsoft 365 Apps for business (corporate)
Microsoft 365 Business Standard (corporate)
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год.
Microsoft 365 Business Basic (corporate)
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
eManual - электронные книги и техническая документация
Работа в Windows и новости компании Microsoft
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100