Страницы

среда, 26 декабря 2012 г.

Собственный компонент для создания OLE-объектов с помощью Transact-SQL

Не секрет, что с помощью хранимых процедур sp_OA... можно создавать в коде экземпляры OLE-объектов, работать с их свойствами, методами, используя в Transact-SQL мощь других языков программирования. Предположим, что нам понадобилось в коде на Transact-SQL решить нетипичную для T-SQL задачу, например изменить дату создания файла. Давайте воспользуемся для решения задачи средствами, например, Visual Basic-а. Итак, создадим в среде разработки на Visual Basic 6.0 новый проект ActiceX dll:




















Назовем проект "EdynakFiles", а класс "Attributes":






















Приступим к написанию кода на Visual Basic. Исходный код класса Attributes такой:

'---------------------------------------------------------------------------------------
'   Класс "Attributes", позволяет менять некоторые атрибуты файла
'---------------------------------------------------------------------------------------
Option Explicit


'---------------------------------------------------------------------------------------
'   Закрытые переменные класса
'---------------------------------------------------------------------------------------

' функции преобразования формата даты
Private Declare Function SystemTimeToFileTime& Lib "kernel32" (lpSystemTIME As SYSTEMTIME, lpFileTime As FILETIME)

Private Declare Function FileTimeToSystemTime& Lib "kernel32" (lpFileTime As FILETIME, lpSystemTIME As SYSTEMTIME)

' функции работы с файлами
Private Declare Function lopen& Lib "kernel32" Alias "_lopen" (ByVal lpFileName As String, ByVal wReadWhite As Long)

Private Declare Function lclose& Lib "kernel32" Alias "_lclose" (ByVal hFile As Long)

Private Declare Function SetFileTime& Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILETIME, _
    lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME)



'---------------------------------------------------------------------------------------
'   Закрытые типы класса
'---------------------------------------------------------------------------------------

' для хранения даты во внутреннем формате
Private Type FILETIME
    dwLowDateTime   As Long
    dwHighDateTime  As Long
End Type

' для хранения даты в системном формате
Private Type SYSTEMTIME
    wYear           As Integer
    wMonth          As Integer
    wDayOfWeek      As Integer
    wDay            As Integer
    wHour           As Integer
    wMinute         As Integer
    wSecond         As Integer
    wMilliseconds   As Integer
End Type


'---------------------------------------------------------------------------------------
'   Открытые методы класса
'---------------------------------------------------------------------------------------

Public Function CreateDateSet(FileName As String, NewDate As Date) As String
    Dim SysTime As SYSTEMTIME, NowTime As FILETIME, handleF As Long, wReadWrite As Long, k As Long
   
    On Error GoTo ErrorHandler
   
    NewDate = DateAdd("h", -4, NewDate)
   
    SysTime.wYear = Year(NewDate)
    SysTime.wMonth = Month(NewDate)
    SysTime.wDay = Day(NewDate)
    SysTime.wHour = Hour(NewDate)
    SysTime.wMinute = Minute(NewDate)
    SysTime.wSecond = Second(NewDate)
   
    ' преобразование даты во внутренний формат
    k = SystemTimeToFileTime(SysTime, NowTime)
   
    ' для изменения атрибута открываем в режиме чтение-запись
    wReadWrite = 2
   
    ' открываем файл
    handleF = lopen&(FileName, wReadWrite)
   
    ' запись нового атрибута
    k = SetFileTime&(handleF, NowTime, NowTime, NowTime)
   
    lclose handleF
    Exit Function

ExitLabel:
    Exit Function
ErrorHandler:
    CreateDateSet = "Ошибка в работе метода CreateDateSet. Номер: " & Cstr(VBA.Err.Number) & ". Описание: " & VBA.Err.Description
    Resume ExitLabel
End Function


Класс подготовлен. Теперь его надо скомпилировать (для этого Visual Studio должна быть открыта от имени администратора для возможности редактирования реестра):























После компиляции библиотеки можно наконец приступить к программированию на Transact-SQL. Сперва нам надо создать OLE объект, то есть экземпляр класса, и работать с его методами, ссылаясь на полученный описатель. Для этого используется хранимая процедуры sp_OACreate. В качестве ее первого параметра можно использовать имя библиотеки, соединенное через точку с именем класса:


declare @classId int, @param int
exec @param = master.dbo.sp_OACreate N'EdynakFiles.Attributes', @classId out



Кроме этого вместо имени библиотеки и класса, можно было бы использовать guid класса, который прописан в реестре. Его можно найти контекстным поиском:















Тогда код может быть таким:

declare @classId int, @param int
exec @param = master.dbo.sp_OACreate N'{52ABE748-1583-4859-9289-CC5C1B3B756E}', @classId out

Для вызова метода воспользуется кодом ниже:
declare @res varchar ( 8000 ), @FileName varchar ( 255 ) = 'C:\Users\EdynakVV\Desktop\101_20121221.xls',
      @NewDate datetime = '2012-12-13 10:14:15'
exec @param = master.dbo.sp_OAMethod @classId, N'CreateDateSet', @res out, @FileName, @NewDate
select @param
exec @param = master.dbo.sp_OADestroy @classId

Задача решена, дату создания файла можно менять. Можно создавать свои собственные библиотеки для решения самых разных задач программирования на стороне сервера (не забывая, конечно, о мощи самого языка Transact-SQL). Отмечу, что в производственной среде следует всегда использовать обработку ошибок, при которой вызов sp_OADestroy будет гарантированно выполнен, если экземпляр класса был создан.

Описанная здесь техника, по-видимому не подойдет для работы на компьютерах с 64-х разрядными операционными системами, поскольку в этом случае код библиотеки на Visual Basic 6.0 требуется скомпилировать с помощью компилятора, предназначенного для соответствующих операционных систем. В таком случае можно попробовать создать аналогичные библиотеки с помощью современных версий Visual Studio, например, на языке C#. Постараюсь рассказать об этом в одной из следующих статей.

Комментариев нет:

Отправить комментарий