Дмитрий Кузан
Добрый день!
Недавно встала задача загружать файлы документов в БД (поле BLOB) в виде OLE-объекта, которого в дальнейшем можно вывести в стандартный OLE контейнер Delphi для просмотра и последующего редактирования.
Первое что встает в голову воспользоватся стандартной функций OleContainer - CreateObjectFromFile.
т.е. сделать что то вроде такого кода
03 |
Stream := TMemoryStream . Create; |
04 |
OleContainer . CreateObjectFromFile(OpenDialog . FileName); |
05 |
OleContainer . SaveToStream(Stream); |
06 |
TableDATA . LoadFromStream(Stream); |
где TableData - это Blob-поле. Всем хорош данный код, но мне он не понравился по 2-м причинам:
1.нужно иметь OleContainer на форме
2.загрузка таким способом происходит довольно медленно, т.к. если OleContainer находится на форме, много времени тратится на лишнии операции (прорисовка и пр)
поэтому хотелось бы загружать файл документа сразу в БД минуя OleContainer, т.е создать внедренный Ole-объект на основе файла документа и поместить его в БД.
Вообщем повозившись полчасика родилось такое решение, которое по производительности обошло загрузку стандартным способом:
02 |
StreamSignature = $434F4442 ; {'BDOC'} |
04 |
TStreamHeader = record |
11 |
PartRect: TSmallRect); |
17 |
Stream : TMemoryStream; |
18 |
FStorage : IStorage; {Интерфейс хранилища} |
19 |
FOleObject: IOleObject; {Интерфейс является основным средством, с помощью которого |
20 |
внедренный объект наделяется базовой функциональностью, |
21 |
и взаимодействует с контейнером хранилища} |
22 |
FLockBytes: ILockBytes; {Интерфейс структурированного хранилища, который |
23 |
служит для доступа к длинным текстовым и |
27 |
Header: TStreamHeader; |
29 |
if OpenDialog . Execute then |
31 |
FN := ExtractFileName(OpenDialog . FileName); |
36 |
{ Доступ к памяти для реализации ILockBytes } |
37 |
OleCheck(CreateILockBytesOnHGlobal( 0 , True , FLockBytes)); |
38 |
{ Создание хранилища IStorage и связка его с реализацией интерфеса |
40 |
OleCheck(StgCreateDocfileOnILockBytes(FLockBytes, |
41 |
STGM_READWRITE or STGM_SHARE_EXCLUSIVE or STGM_CREATE, 0 , FStorage)); |
42 |
// Создание внедеренного объекта из файла |
43 |
OleCheck(OleCreateFromFile(GUID_NULL, PWideChar (OpenDialog . FileName), |
44 |
IOleObject, OLERENDER_NONE, nil , nil , FStorage, FOleObject)); |
45 |
OleCheck(GetHGlobalFromILockBytes(FLockBytes, DataHandle)); |
48 |
{ Создаем поток в памяти } |
49 |
Stream := TMemoryStream . Create; |
51 |
Header . Signature := StreamSignature; |
52 |
Header . DrawAspect := DVASPECT_CONTENT; { Контент } |
53 |
Header . DataSize := GlobalSize(DataHandle); |
54 |
// Записываем заголовок + контент |
55 |
Stream . WriteBuffer(Header, SizeOf(Header)); |
57 |
Buffer := GlobalLock(DataHandle); |
58 |
// Записываем размер заголовка |
59 |
Stream . WriteBuffer(Buffer^, Header . DataSize); |
61 |
GlobalUnlock(DataHandle); |
65 |
Table NAME . Value := FN; |
66 |
Table DATA . LoadFromStream(Stream); |