显示Microsoft Access“OLE对象”在我的申请 [英] Display Microsoft Access "OLE Object" in my application

查看:393
本文介绍了显示Microsoft Access“OLE对象”在我的申请的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含OLE对象字段的Access数据库。我需要提取这个字段的内容作为一个图像。什么类型最初放置在OLE字段中无关紧要。我只需要一个代表该对象的图像。



主要目标是将OLE对象字段移动到存储在blob字段。



我已经找到一些解析blob的示例代码,并尝试提取底层文件。我真的在寻找使用OLE对象的东西,而不是试图解决它们。



stackoverflow有两个类似的问题:

转换OLE图像对象从MS Access在.NET中使用

从Access DB提取OLE对象(pdf)



我打开这个问题主要是发布我当前的Delphi代码,看看是否有比我当前的代码更好的方法,如果没有,帮助别人。



我使用的是Delphi 2007,但是使用任何语言的代码都是有帮助的。

解决方案>

以下是我正在使用的解决方案。其起点来自 Ms Ole Fields on Ms about.com网站



几个注释:




  • 访问似乎使用OLE1存储对象标准不是OLE2。除了上述的帖子以外,我找不到任何确认。

  • 访问在OLE1字段前添加自己的标题。再次,我没有发现除帖子之外的任何文档。

  • 我找不到直接使用OLE1对象的方法,我需要将其转换为OLE2对象。为了做到这一点,我需要和OLE1流似乎没有在VCL或Win API中实现任何地方。实现是直接从帖子中获取的,我不能说我理解它正在做的一切。



一旦你有一个IOLEObject如果您可以使用OleDraw函数来绘制自己的画布。在这一点上,你有一个图像,并且关闭并运行。如果您只想显示对象,您可以使用TOLEContainer组件,并处理图形。



这是使用该单元的代码。我有一个ADO表,其类型为TBlobField的字段对象名为AdoTable1Photo。

  procedure TForm2.ADOTable1AfterScroll(DataSet:TDataSet); 
var
Bmp:TBitmap;
Jpg:TJpegImage;

OleObject:IOleObject;
DataObject:IDataObject;
CreateInfo:TCreateInfo;
begin

如果AdoTable1Photo.BlobSize = 0然后
exit;

OleObject:= OleFieldToObject(AdoTable1Photo);

//如果要保存图像文件绘制,则将ole对象绘制到
//一个位图画布,然后保存结果。可用于将
//一个字段转换为真实图像Blob而不是OLE对象类型。
Bmp:= TBitmap.Create();
Jpg:= TJpegImage.Create();

try
DrawOleOnBmp(OleObject,Bmp);
Jpg.Assign(Bmp);
Jpg.SaveToFile('C:\temp\test.jpg');
finally
Bmp.Free;
Jpg.Free;
结束

//如果只是尝试显示没有转换的结果,可以将
// OleObject附加到将处理图形的OleContainer组件。
//我找不到一个简单的方法来直接做到这一点。我需要使用
// IDataObject interace与CreateInfo记录。

如果成功(OleObject.QueryInterface(IDataObject,DataObject))然后
begin
//使用IDataObject
加载OLE容器控件CreateInfo.CreateType:= ctFromData;
CreateInfo.ShowAsIcon:= false;
CreateInfo.DataObject:= DataObject;
OleContainer.CreateObjectFromInfo(CreateInfo);
结束

OleObject:= nil;
结束

这里是将字段转换为IOleObject的单位。很难的部分是提取分流头并将其转换为OLE2对象的流。一旦完成,我真的只使用两个函数:OLELoad和OLEDraw。

 单元MSAccessOleObject; 

接口
使用ActiveX,Windows,Classes,ComObj,DB,Graphics;

//这个文件是这里发布的源代码的修改版本:
// http://forums.about.com/ab-delphi/messages?lgnF=y&msg = 1865.1

// -------------------------------------- ---------------------------------------
//从Ole.h转换
//
//从OleConvertOLESTREAMToIStorage OLE中使用OLE函数
//到目前为止,我知道Access转换OLE1对象中的OLE2对象
//
// So为了阅读这种类型的字段,我们必须将OLE1格式
//转换为OLE2格式,因此我们需要OleConvertOLESTREAMToIStorage
//并将OLE对象写入Field,我们需要
// OleConvertIStorageToOLESTREAM OLE功能。
//这里的代码仅用于阅读Ole Object字段,但它也适用于
//来编写它们。
//
// OLE.h定义一个使用vtable和回调函数的OLE流。 I
//在VCL中找不到实现OLE v1 Stream的类。
type
POleStreamVtbl = ^ TOleStreamVtbl;
TOleStreamVtbl = record
获取:指针;
放:指针;
结束

POle1Stream = ^ TOle1Stream;
TOle1Stream = record
pvt:POleStreamVtbl;
lpData:指针; //链接到.MDB文件中的数据
dwSize:Integer; // OLE流长度(相对于位置)
end;

POleStream = ^ TPOleStream;
TPOleStream = record
lpstbl:POleStreamVtbl;
结束

// ---------------------------------------- -------------------------------------
// Microsoft Access Field Header
//
// Access将头信息添加到实际的OLE流之前。
//我们需要读取它来获取大小,以便找到
//实际OLE流的开始。
type
TKind = record
case
0的整数:(oot:DWord); // OLE对象类型代码(OT_LINK,OT_EMBEDDED,OT_STATIC)
1:(lobjTyp:LongInt); //在我们的例子中:OT_EMBEDDED
end;

PAccessOleObjectHeader = ^ TAccessOleObjectHeader;
TAccessOleObjectHeader = record
typ:WORD; //类型签名(0x1C15)
cbHdr:WORD; // sizeof(struct OLEOBJECTHEADER)+ cchName + cchClass
lobjType:TKind; // OLE对象类型代码(OT_STATIC,OT_LINKED,OT_EMBEDDED)
cchName:WORD; //对象名称中的字符数计数(CchSz(szName)+ 1))
cchClass:WORD; //类名中的字符数(CchSz(szClss)+ 1))
ibName:WORD; //结构中的对象名称的偏移量(sizeof(OLEOBJECTHEADER)
ibClass:WORD; //结构中类名的偏移量(ibName + cchName)
ptSize:TSmallPoint; // Object的原始大小(MM_HIMETRIC )
end;


函数CreateOle1Stream(pStm:IStream; dwSize:Integer):POle1Stream;
procedure DeleteOle1Stream(var Ole1Stream:POle1Stream);

// OLE1 Stream的回调函数
函数Get(OleStream:POLESTREAM; Pb:Pointer; cb:Integer):Integer; stdcall;
函数Put(OleStream:POLESTREAM; const Pb:Pointer ; cb:Integer):Integer; stdcall;

函数OleFieldToObject(AdoField:TBlobField):IOleObject;
程序DrawOleOnBmp(Ole:IOleObject; Bmp:TBitmap);

实现

使用Sysutils;

{
CreateOle1Stream
------------------ -------------------------------------------------- -------
}
函数CreateOle1Stream(pStm:IStream; dwSize:Integer):POLE 1流
var
cb:Int64;
begin
结果:= new(POle1Stream);
Result.pvt:= new(POleStreamVtbl);
Result.pvt.Get:= @Get;
Result.pvt.Put:= @Put;
Result.dwSize:= dwSize;
Result.lpData:=指针(pStm);

//寻求流的开始
IStream(Result.lpData).Seek(0,STREAM_SEEK_SET,cb);
结束


{
DeleteOle1Stream
---------------------------- -----------------------------------------------
}
procedure DeleteOle1Stream(var Ole1Stream:POle1Stream); // Dispose then OLE1 Stream
begin
if Ole1Stream = Nil then
exit;

Dispose(Ole1Stream ^ .pvt);
Dispose(Ole1Stream);
结束

{

-------------------------------- -------------------------------------------
回调函数Ole1Stream
}
函数Put(OleStream:POLESTREAM; const Pb:Pointer; cb:Integer):Integer;标准
Var
pStream:POle1Stream;
ulBytesWritten:longInt;
begin
pStream:= POle1Stream(OleStream);

if(pStream = Nil)或(pStream ^ .lpData = Nil)或(pb = Nil)然后
begin
结果:= 0;
退出;
结束

ulBytesWritten:= 0;
如果IStream(pStream ^ .lpData).Write(Pb,cb,@ ulBytesWritten)< S_OK然后
begin
结果:= 0;
退出;
结束

pStream ^ .dwSize:= pStream ^ .dwSize + ulBytesWritten;
结果:= cb;
结束

{
获取
-------------------------------- -------------------------------------------
回调函数Ole1Stream
}
function Get(OleStream:POLESTREAM; Pb:Pointer; cb:Integer):Integer;标准
Var
pStream:POle1Stream;
ulBytesRead:LongInt;
begin
pStream:= POle1Stream(OleStream);
if(pStream = Nil)或(pStream ^ .lpData = Nil)或(pStream ^ .dwSize< cb)
然后
begin
结果:= 0;
退出;
结束

ulBytesRead:= 0;
如果IStream(pStream ^ .lpData).Read(pb,cb,@ulBytesRead)<> S_OK然后
begin
结果:= 0;
退出;
结束

pStream ^ .dwSize:= pStream ^ .dwSize-ulBytesRead;
结果:= cb;

end;

{
OleFieldToObject
-------------------------------- -------------------------------------------
通过ADO字段的OLE对象类型,并获取IOleObject
接口。然后,您可以将该对象附加到OleContanier,
让它绘制自己或使用DrawOleOnBmp函数来获取您自己的位图

}
函数OleFieldToObject(AdoField:TBlobField):IOleObject;
var

AccessHeader:TAccessOleObjectHeader;

FullAdoStream:TMemoryStream;
ObjectStream:TMemoryStream;

StreamAdapter:TStreamAdapter;
StreamInterface:IStream;
Ole1Stream:POle1Stream;

OleBytes:ILockBytes;
OleStorage:IStorage;
OleObject:IOleObject;

begin

FullAdoStream:= nil;
ObjectStream:= nil;
StreamAdapter:= nil;
StreamInterface:= nil;
Ole1Stream:= nil;

try
//我们需要一个IStorage接口,用于加载OLEObject
OleCheck(CreateILockBytesOnHGlobal(0,true,OleBytes));
OleCheck(StgCreateDocfileOnILockBytes(OleBytes,
STGM_Create或STGM_READWRITE或STGM_SHARE_EXCLUSIVE或STGM_DIRECT,0,OleStorage));


//我们需要从字段中获取数据。 Microsoft Access存储一个OLE1字段
//而不是当前的OLE2格式。它还将它自己的头添加到对象上。
//我们需要 - 提取流,删除头,将流包装在
// IStreamInterface中,将其包含在内部和OLE1Stream对象中。

FullAdoStream:= TMemoryStream.Create();
AdoField.SaveToStream(FullAdoStream);

FullAdoStream.Seek(0,soBeginning);
FullAdoStream.ReadBuffer(AccessHeader,sizeof(TAccessOleObjectHeader));

//我们可以检查AccessHeader.typ = $ 1C15,但如果格式不是
//对,以后会出错。


//寻找标题,然后将流的其余部分复制到新的流。
FullAdoStream.Seek(AccessHeader.cbHdr,soBeginning);
ObjectStream:= TMemoryStream.Create();
ObjectStream.CopyFrom(FullAdoStream,FullAdoStream.Size - FullAdoStream.Position);

StreamAdapter:= TStreamAdapter.Create(ObjectStream,soReference);
StreamInterface:= StreamAdapter as IStream;
Ole1Stream:= CreateOle1Stream(StreamInterface,ObjectStream.Size);

//现在将OLE1流转换为OLE2(IStorage)并加载IOleObject
//这个函数似乎很慢,但是我找不到任何东西要更改
//或任何其他使用的功能。
OleCheck(OleConvertOLESTREAMToIStorage(Ole1Stream,OleStorage,Nil));
OleCheck(OleLoad(OleStorage,IOleObject,nil,OleObject));

finally
DeleteOle1Stream(Ole1Stream);
StreamInterface:= nil;
StreamAdapter:= nil;
ObjectStream.Free;
FullAdoStream.Free;
结束

result:= OleObject;

end;


{
DrawOleOnBmp
---------------------------- -----------------------------------------------
取OleObject并将其绘制到位图画布上。位图将被调整为
以匹配OLE对象的正常大小。
}
程序DrawOleOnBmp(Ole:IOleObject; Bmp:TBitmap);
var
ViewObject2:IViewObject2;
ViewSize:TPoint;
AdjustedSize:TPoint;

DC:HDC;
R:TRect;
begin

如果成功(Ole.QueryInterface(IViewObject2,ViewObject2))然后
begin
ViewObject2.GetExtent(DVASPECT_CONTENT,-1,nil,ViewSize);

DC:= GetDC(0);
AdjustedSize.X:= MulDiv(ViewSize.X,GetDeviceCaps(DC,LOGPIXELSX),2540);
AdjustedSize.Y:= MulDiv(ViewSize.Y,GetDeviceCaps(DC,LOGPIXELSY),2540);
ReleaseDC(0,DC);

Bmp.Height:= AdjustedSize.Y;
Bmp.Width:= AdjustedSize.X;

SetRect(R,0,0,Bmp.Width,Bmp.Height);

OleDraw(Ole,DVASPECT_CONTENT,Bmp.Canvas.Handle,R);
end
else
begin
raise Exception.Create('无法获取OleObject上的IViewObject2 interfact);
结束

end;

结束。


I have an an Access database that contains an OLE Object field. I need to extract the contents of this field as an image. It does not matter what type was originally placed in the OLE Field. I just need an image that represents what that object looks like.

The main goal of this is to move away from the OLE Object field to a more standard image stored in a blob field.

I have found some example code that parses the blob and tries to extract the underlying file. I am really looking for something that uses the OLE objects as they were intended instead of trying to work around them.

There are two similar questions on stackoverflow:
Converting an OLE Image Object from MS Access for use in .NET
Extract OLE Object (pdf) from Access DB

I'm opening this question mainly as a place to post my current Delphi code to see if there is a better way than my current code and to help others if not.

I am using Delphi 2007 but code in any language would be helpful.

解决方案

Below is the solution that I am using. The starting point for this came from the Ms Access Ole Fields on the about.com site.

A few notes:

  • Access seems to store the object using the OLE1 standard not the OLE2. I could not find any confirmation of this anywhere other than the post mentioned above.
  • Access appends its own header in front of the OLE1 field. Again I did not find any documentation other than the post.
  • I could not find a way to use the OLE1 object directly, I needed to convert it to an OLE2 object. In order to do that I needed and OLE1 stream which did not seem to be implemented in the VCL or Win API anywhere. The implementation is taken directly from the post, I can't say I understand everything it is doing.

Once you have a IOLEObject in had you can use the OleDraw function to draw to your own canvas. At that point you have an image and are off and running. If you just want to display the object you can use the TOLEContainer component and let it deal with the drawing.

Here is the code that uses the unit. I have an ADO table with a field object of type TBlobField named AdoTable1Photo.

procedure TForm2.ADOTable1AfterScroll(DataSet: TDataSet);
var
  Bmp: TBitmap;
  Jpg: TJpegImage;

  OleObject: IOleObject;
  DataObject: IDataObject;
  CreateInfo: TCreateInfo;
begin

  if AdoTable1Photo.BlobSize = 0 then
    exit;

  OleObject := OleFieldToObject(AdoTable1Photo);

  // If you want to save out an image file draw let the ole object draw to
  // a bitmap canvas and then save the results.  Could be used for converting
  // a field to a true image blob instead of a OLE Object type.
  Bmp := TBitmap.Create();
  Jpg := TJpegImage.Create();

  try
    DrawOleOnBmp(OleObject, Bmp);
    Jpg.Assign(Bmp);
    Jpg.SaveToFile('C:\temp\test.jpg');
  finally
    Bmp.Free;
    Jpg.Free;
  end;

  // If just trying to display the results without converting you can attach
  // the OleObject to a OleContainer component that will handle the drawing.
  // I could not find an easy way to do this directly.  I needed to use the
  // IDataObject interace with the CreateInfo record.

  if Succeeded(OleObject.QueryInterface(IDataObject, DataObject)) then
  begin
    // Load the OLE Container control by using the IDataObject
    CreateInfo.CreateType := ctFromData;
    CreateInfo.ShowAsIcon := false;
    CreateInfo.DataObject := DataObject;
    OleContainer.CreateObjectFromInfo(CreateInfo);
  end;

  OleObject := nil;
end;

And here is the unit that is converting the field to the IOleObject. The hard part is extracting the stream splitting out the header and converting it to an OLE2 object. Once that is done there are really only two functions I am using: OLELoad and OLEDraw.

unit MSAccessOleObject;

interface
uses ActiveX, Windows, Classes, ComObj, DB, Graphics;

  // This file is a modified version of the source code posted here:
  // http://forums.about.com/ab-delphi/messages?lgnF=y&msg=1865.1

  //-----------------------------------------------------------------------------
  // Converted from Ole.h
  // 
  // Used inside from OleConvertOLESTREAMToIStorage OLE Function
  // As far I know the Access Converts the OLE2 objects in OLE1 Objects
  //
  // So for read this Kind of field we must covert the OLE1 format
  // to OLE2 format so we need the OleConvertOLESTREAMToIStorage
  // and to write an OLE object to Field we need the
  // OleConvertIStorageToOLESTREAM OLE function.
  // The code here is only for reading "Ole Object" fields, but it coudld adapted
  // to write them as well. 
  //
  // OLE.h define a OLE stream that uses a vtable and callback functions. I
  // could not find a class in the VCL that implemented the OLE v1 Stream.
  type
    POleStreamVtbl = ^TOleStreamVtbl;
    TOleStreamVtbl = record
      Get: Pointer;
      Put: Pointer;
    end;

    POle1Stream = ^TOle1Stream;
    TOle1Stream = record
      pvt: POleStreamVtbl;
      lpData: Pointer; // Link to Data in .MDB file
      dwSize: Integer; // OLE Stream length (relative to position)
    end;

    POleStream = ^TPOleStream;
    TPOleStream = record
      lpstbl: POleStreamVtbl;
    end;

  //-----------------------------------------------------------------------------
  //    Microsoft Access Field Header
  //
  //  Access adds header information in front of the actual OLE stream.
  //  We need to read it to get the size in order to find the start of
  //  the actual OLE stream.
  type
    TKind=record
      case Integer of
        0: (oot: DWord); // OLE Object type code (OT_LINK, OT_EMBEDDED, OT_STATIC)
        1: (lobjTyp: LongInt); // in our case: OT_EMBEDDED
      end;

    PAccessOleObjectHeader=^TAccessOleObjectHeader;
    TAccessOleObjectHeader = record
      typ: WORD;       // Type signature (0x1C15)
      cbHdr: WORD;     // sizeof(struct OLEOBJECTHEADER) + cchName +cchClass
      lobjType: TKind; // OLE Object Type Code (OT_STATIC, OT_LINKED,OT_EMBEDDED)
      cchName: WORD;   // Count of characters in object Name (CchSz(szName) + 1))
      cchClass: WORD;  // Count of characters in class Name  (CchSz(szClss) + 1))
      ibName: WORD;    // Offset of object name in structure  (sizeof(OLEOBJECTHEADER)
      ibClass: WORD;   // Offset of class name in structure  (ibName +cchName)
      ptSize: TSmallPoint; // Original size of Object (MM_HIMETRIC)
    end;


  function CreateOle1Stream(pStm: IStream; dwSize: Integer): POle1Stream;
  procedure DeleteOle1Stream(var Ole1Stream: POle1Stream);

  // Callback Functions for OLE1 Stream
  function Get(OleStream: POLESTREAM; Pb:Pointer; cb:Integer): Integer; stdcall;
  function Put(OleStream: POLESTREAM; const Pb:Pointer; cb:Integer): Integer; stdcall;

  function OleFieldToObject(AdoField: TBlobField): IOleObject;
  procedure DrawOleOnBmp(Ole: IOleObject; Bmp: TBitmap);

implementation

uses Sysutils;

{
  CreateOle1Stream
  ---------------------------------------------------------------------------
}
function CreateOle1Stream(pStm:IStream; dwSize:Integer): POLE1Stream;
var
  cb: Int64;
begin
  Result := new(POle1Stream);
  Result.pvt := new(POleStreamVtbl);
  Result.pvt.Get := @Get;
  Result.pvt.Put := @Put;
  Result.dwSize := dwSize;
  Result.lpData := Pointer(pStm);

  // Seek to the start of the stream
  IStream(Result.lpData).Seek(0,STREAM_SEEK_SET,cb);
end;


{
  DeleteOle1Stream
  ---------------------------------------------------------------------------
}
procedure DeleteOle1Stream(var Ole1Stream: POle1Stream); // Dispose then OLE1 Stream
begin
  if Ole1Stream = Nil then
    exit;

  Dispose(Ole1Stream^.pvt);
  Dispose(Ole1Stream);
end;

{
  Put
  ---------------------------------------------------------------------------
  Callback function for Ole1Stream
}
function Put(OleStream: POLESTREAM; const Pb:Pointer; cb:Integer): Integer; stdcall;
Var
  pStream: POle1Stream;
  ulBytesWritten: longInt;
begin
  pStream:=POle1Stream(OleStream);

  if (pStream = Nil) or (pStream^.lpData=Nil) or (pb=Nil) then
  begin
    Result:=0;
    exit;
  end;

  ulBytesWritten:=0;
  if IStream(pStream^.lpData).Write(Pb,cb,@ulBytesWritten) <> S_OK then
  begin
    Result:=0;
    exit;
  end;

  pStream^.dwSize:=pStream^.dwSize+ulBytesWritten;
  Result:=cb;
end;

{
  Get
  ---------------------------------------------------------------------------
  Callback function for Ole1Stream
}
function Get(OleStream: POLESTREAM; Pb: Pointer; cb: Integer): Integer; stdcall;
Var
  pStream: POle1Stream;
  ulBytesRead: LongInt;
begin
  pStream := POle1Stream(OleStream);
  if (pStream=Nil) or (pStream^.lpData=Nil) or (pStream^.dwSize < cb)
  then
  begin
    Result := 0;
    exit;
  end;

  ulBytesRead := 0;
  if IStream(pStream^.lpData).Read(pb, cb, @ulBytesRead) <> S_OK then
  begin
    Result := 0;
    exit;
  end;

  pStream^.dwSize := pStream^.dwSize-ulBytesRead;
  Result := cb;

end;

{
  OleFieldToObject
  ---------------------------------------------------------------------------
  Pass in the ADO field of the "OLE Object" type and get the IOleObject
  interface back.  You can then attached that object to a OleContanier and
  let it draw itself or use the DrawOleOnBmp function to get your own bitmap
  that can be used by itself.
}
function OleFieldToObject(AdoField: TBlobField): IOleObject;
var

  AccessHeader: TAccessOleObjectHeader;

  FullAdoStream: TMemoryStream;
  ObjectStream: TMemoryStream;

  StreamAdapter: TStreamAdapter;
  StreamInterface: IStream;
  Ole1Stream: POle1Stream;

  OleBytes: ILockBytes;
  OleStorage: IStorage;
  OleObject: IOleObject;

begin

  FullAdoStream := nil;
  ObjectStream := nil;
  StreamAdapter := nil;
  StreamInterface := nil;
  Ole1Stream := nil;

  try
    // We need a IStorage Interface that will be used to load the OLEObject
    OleCheck( CreateILockBytesOnHGlobal(0, true, OleBytes) );
    OleCheck( StgCreateDocfileOnILockBytes(OleBytes,
      STGM_Create or STGM_READWRITE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT,  0, OleStorage) );


    // We need to get the data out of the field.  Microsoft Access stores a OLE1 field
    // and not the current OLE2 format.  It also adds it's own header on the object.
    // We need to - extract the stream, remove the header, wrap the stream in an
    // IStreamInterface, wrap that inside and OLE1Stream object.

    FullAdoStream := TMemoryStream.Create();
    AdoField.SaveToStream(FullAdoStream);

    FullAdoStream.Seek(0, soBeginning);
    FullAdoStream.ReadBuffer(AccessHeader, sizeof(TAccessOleObjectHeader));

    // We could check if AccessHeader.typ = $1C15 but if the format is not
    // right something will go wrong later.


    // Seek past the header and then copy the rest of the stream to a new stream.
    FullAdoStream.Seek(AccessHeader.cbHdr, soBeginning);
    ObjectStream := TMemoryStream.Create();
    ObjectStream.CopyFrom(FullAdoStream, FullAdoStream.Size - FullAdoStream.Position);

    StreamAdapter := TStreamAdapter.Create(ObjectStream, soReference);
    StreamInterface := StreamAdapter as IStream;
    Ole1Stream := CreateOle1Stream(StreamInterface, ObjectStream.Size);

    // Now convert the OLE1 stream to OLE2 (IStorage) and load the IOleObject
    // This function seems to be slow, but I can't find anything to change
    // or any other function to use. 
    OleCheck( OleConvertOLESTREAMToIStorage(Ole1Stream, OleStorage, Nil) );
    OleCheck( OleLoad(OleStorage, IOleObject, nil, OleObject) );

  finally
    DeleteOle1Stream(Ole1Stream);
    StreamInterface := nil;
    StreamAdapter := nil;
    ObjectStream.Free;
    FullAdoStream.Free;
  end;

  result := OleObject;

end;


{
  DrawOleOnBmp
  ---------------------------------------------------------------------------
  Take a OleObject and draw it to a bitmap canvas.  The bitmap will be sized
  to match the normal size of the OLE Object.
}
procedure DrawOleOnBmp(Ole: IOleObject; Bmp: TBitmap);
var
  ViewObject2: IViewObject2;
  ViewSize: TPoint;
  AdjustedSize: TPoint;

  DC: HDC;
  R: TRect;
begin

  if Succeeded(Ole.QueryInterface(IViewObject2, ViewObject2)) then
  begin
    ViewObject2.GetExtent(DVASPECT_CONTENT, -1, nil, ViewSize);

    DC := GetDC(0);
    AdjustedSize.X := MulDiv(ViewSize.X, GetDeviceCaps(DC, LOGPIXELSX), 2540);
    AdjustedSize.Y := MulDiv(ViewSize.Y, GetDeviceCaps(DC, LOGPIXELSY), 2540);
    ReleaseDC(0, DC);

    Bmp.Height := AdjustedSize.Y;
    Bmp.Width := AdjustedSize.X;

    SetRect(R, 0, 0, Bmp.Width, Bmp.Height);

    OleDraw(Ole, DVASPECT_CONTENT, Bmp.Canvas.Handle, R);
  end
  else
  begin
    raise Exception.Create('Could not get the IViewObject2 interfact on the OleObject');
  end;

end;

end.

这篇关于显示Microsoft Access“OLE对象”在我的申请的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆