从 TOleContainer 中提取位图?

3
我正在尝试使用IDataObject的GetData方法从TOleContainer中提取位图。
 OleContainer1.CreateObject('Paint.Picture', false);
 OleContainer1.OleObjectInterface.QueryInterface(IDataObject, DataObject);

DataObject使用DATADIR_GET的EnumFormatEtc返回以下内容:

 cfFormat, ptd, dwAspect, lIndex, tymed

 CF_METAFILEPICT, nil, DVASPECT_CONTENT, -1, TYMED_MFPICT
 CF_DIB, nil, DVASPECT_CONTENT, -1, TYMED_HGLOBAL or TYMED_ISTREAM
 CF_BITMAP, nil, DVASPECT_CONTENT, -1, TYMED_HGLOBAL

但是当我执行以下操作时:

FormatEtc.cfFormat := CF_BITMAP;
FormatEtc.ptd := nil;
FormatEtc.dwAspect := DVASPECT_CONTENT;
FormatEtc.lIndex := -1;
FormatEtc.tymed := TYMED_HGLOBAL;

OleCheck(DataObject.GetData(FormatEtc, StorageMedium));

我遇到了“Invalid FORMATETC stucture”错误。我做错了什么?

尝试按照此线程中的建议,将媒体类型从TYMED_HGLOBAL替换为TYMED_GDI - TLama
我已经尝试过了。同样的错误。 - forsajt
另一种方法是:https://dev59.com/qk3Sa4cB1Zd3GeqPy98A - James L.
1个回答

1

我做的和你试图通过使用在这里找到的代码来完成的是相同的事情。在我的情况下,我发现最好采取以下方法,该方法使用提供的链接中的DrawOleOnBmp():

oleMain.UpdateObject;
if oleMain.OleObjectInterface = nil then
  raise Exception.Create('OLE Container is empty.');
DrawOleOnBmp(oleMain.OleObjectInterface, imgMain.Bitmap);
imgMain.Bitmap.SaveToFile('Filename.bmp');

这里的oleMain是一个TOleContainer,而imgMain是一个TImage32。两者都在表单上可见...

为了方便起见,这里提供了链接中@MarkElder编写的方法:

{
  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: TBitmap32);
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;

    Bmp.FillRect(0, 0, Bmp.Width, Bmp.Height, clWhite);

    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;

感谢您的输入。我想这个方法可以行得通,但是有一件事情,您知道GetData失败的原因吗?似乎与TYMED_HGLOBAL有关,因为当我将CF_BITMAP更改为CF_DIB并将TYMED_HGLOBAL更改为TYMED_ISTREAM时,我能够成功检索数据。另外,我还想写回数据,这只有通过IDataObject接口才能实现,对吗? - forsajt
我没怎么用过TOleContainer,所以在使用IDataObject接口方面不是专家。但是去年七月份我尝试将RTF文档转换为另一种格式。其中许多包含OLE对象。当我的计算机上没有安装一个OLE对象的服务器时,只有在这种情况下我才看到“Invalid FORMATETC stucture”。如果您的错误是由于同样的问题(缺少OLE服务器)引起的,则无法通过代码消除该错误。OLE服务器必须存在才能解析和渲染OLE数据。 - James L.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接