Загрузка файла в БД в виде внедренного OLE-объекта без использование стандартного OleContainer

Источник: deeptown12
Дмитрий Кузан

Добрый день!
Недавно встала задача загружать файлы документов в БД (поле BLOB) в виде OLE-объекта, которого в дальнейшем можно вывести в стандартный OLE контейнер Delphi для просмотра и последующего редактирования.

Первое что встает в голову воспользоватся стандартной функций OleContainer - CreateObjectFromFile.

т.е. сделать что то вроде такого кода

01  Table.Append;  
02  try 
03  Stream := TMemoryStream.Create;  
04  OleContainer.CreateObjectFromFile(OpenDialog.FileName);  
05  OleContainer.SaveToStream(Stream);  
06  TableDATA.LoadFromStream(Stream);  
07  finally 
08   Stream.Free;  
09  end;  
10  Table.Post; 

где  TableData - это Blob-поле. Всем хорош данный код, но мне он не понравился по 2-м причинам:
1.нужно иметь OleContainer на форме
2.загрузка таким способом происходит довольно медленно, т.к. если OleContainer находится на форме, много времени тратится на лишнии операции (прорисовка и пр)
поэтому хотелось бы загружать файл документа сразу в БД минуя OleContainer, т.е создать внедренный Ole-объект на основе файла документа и поместить его в БД.

Вообщем повозившись полчасика родилось такое решение, которое по производительности обошло загрузку стандартным способом:

01  const 
02   StreamSignature = $434F4442; {'BDOC'} 
03  type 
04   TStreamHeader = record 
05  case Integer of 
06    0: ( { New } 
07    Signature: Integer;  
08    DrawAspect: Integer;  
09    DataSize: Integer);  
10    1: ( { Old } 
11     PartRect: TSmallRect);  
12  end;  
13  var 
14   ID : Integer;  
15   fDocOLE : TfDocOLE;  
16   FN : string;  
17   Stream : TMemoryStream;  
18   FStorage : IStorage; {Интерфейс хранилища} 
19   FOleObject: IOleObject; {Интерфейс является основным средством, с помощью которого  
20                            внедренный объект наделяется базовой функциональностью,  
21                            и взаимодействует с контейнером хранилища} 
22   FLockBytes: ILockBytes; {Интерфейс структурированного хранилища, который  
23                            служит для доступа к длинным текстовым и  
24                            двоичным данным} 
25   DataHandle: HGlobal;  
26   Buffer: Pointer;  
27   Header: TStreamHeader;  
28  begin 
29  if OpenDialog.Execute then 
30  begin 
31   FN := ExtractFileName(OpenDialog.FileName);  
32   FOleObject := nil;  
33   FStorage := nil;  
34   FLockBytes := nil;  
35    
36   { Доступ к памяти для реализации ILockBytes } 
37   OleCheck(CreateILockBytesOnHGlobal(0, True, FLockBytes));  
38   { Создание хранилища IStorage и связка его с реализацией интерфеса  
39   ILockBytes } 
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));  
46    
47   try 
48   { Создаем поток в памяти } 
49   Stream := TMemoryStream.Create;  
50   Stream.Position := 0;  
51   Header.Signature := StreamSignature;  
52   Header.DrawAspect := DVASPECT_CONTENT; { Контент } 
53   Header.DataSize := GlobalSize(DataHandle);  
54   // Записываем заголовок + контент  
55   Stream.WriteBuffer(Header, SizeOf(Header));  
56   try 
57    Buffer := GlobalLock(DataHandle);  
58    // Записываем размер заголовка  
59    Stream.WriteBuffer(Buffer^, Header.DataSize);  
60   finally 
61    GlobalUnlock(DataHandle);  
62   end;  
63    
64   Table.Append;  
65   Table NAME.Value := FN;  
66   Table DATA.LoadFromStream(Stream);  
67   Table.Post;  
68  finally 
69   Stream.Free;  
70  end;  
71  end; { OpenDialog } 

Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=28110