关于COM中IPictureDisp和Tbitmap的传递和转换?

aniugee 2008-10-28 05:52:34
COM控件中封装了视频功能,当接收到视频数据后,会将视频数据画到一个Tbitmap上,然后产生一个事件,将Tbitmap传递出去。
当然COM并不支持Tbitmap类型的参数,比较类似的是IPictureDisp,请教大家如何进行转换的接收?
100分奉上。
...全文
572 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
cn0754 2011-02-01
  • 打赏
  • 举报
回复
看看看看看看
aniugee 2008-10-29
  • 打赏
  • 举报
回复
留点时间给大家想再讨论一下,没什么问题下午就结贴了。
aniugee 2008-10-29
  • 打赏
  • 举报
回复
但上面的代码远程传递参数肯定是比较好的选择。
aniugee 2008-10-29
  • 打赏
  • 举报
回复
其实我还有一个写法,只是个人认为效率不高,贴出来给大家分享
MemoryStreamToOleVariant和OleVariantToMemoryStream这两个函数大家BAIDU一下就有了。

function Ttestimage.Get_OleImage: OleVariant;
var
BitMap:TBitMap;
DeskWnd, DeskDC:LongWord;
MemoryStream: TMemoryStream;
begin
DeskWnd:=GetDesktopWindow();
DeskDC:=GetDC(DeskWnd);
BitMap:=TBitMap.Create;
try
BitMap.Width:=Screen.Width;
BitMap.Height:=Screen.Height;
Bitblt(BitMap.Canvas.Handle,0,0,Screen.Width,Screen.Height,
DeskDC,0,0,SRCCOPY);
finally
ReleaseDC(DeskWnd,DeskDC);
end;

MemoryStream := TMemoryStream.Create;
try
BitMap.SaveToStream(MemoryStream);
Result := MemoryStreamToOleVariant(MemoryStream);
finally
MemoryStream.Free;
BitMap.Free;
end;
end;

调用代码:
procedure TForm1.Button2Click(Sender: TObject);
var
BinaryData : OleVariant;
Stream: TMemoryStream;
Jpeg :TJpegimage;
BitMap:TBitMap;
begin
BinaryData:=Fobject.OleImage;
try
Stream := OleVariantToMemoryStream(BinaryData);
Stream.Position := 0;
try
BitMap:=TBitMap.Create;
BitMap.LoadFromStream(Stream);
try
Jpeg :=TJpegimage.Create;
Jpeg.Assign(BitMap);
Jpeg.CompressionQuality := 100;
Jpeg.Compress;
Image1.Picture.Assign(Jpeg);
finally
Jpeg.Free;
end;
finally
BitMap.Free;
end;
finally
Stream.Free;
end;
end;
aniugee 2008-10-29
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 unsigned 的回复:]
在对端有没有从IPictureDisp到TPicture的还原?
[/Quote]
有还原
SetOlePicture(Image1.Picture,Fobject.image);
这句就是,只不过会出现cpu调试窗口,并没有还原成功,但也不报错,我也不清楚为什么。
aniugee 2008-10-29
  • 打赏
  • 举报
回复

function Ttestimage.Get_MyimageHandle: SYSINT;
var
BitMap:TBitMap;
DeskWnd, DeskDC:LongWord;
begin
DeskWnd:=GetDesktopWindow();
DeskDC:=GetDC(DeskWnd);
BitMap:=TBitMap.Create;
try
BitMap.Width:=Screen.Width;
BitMap.Height:=Screen.Height;
Bitblt(BitMap.Canvas.Handle,0,0,Screen.Width,Screen.Height,
DeskDC,0,0,SRCCOPY);
finally
ReleaseDC(DeskWnd,DeskDC);
end;
result:=BitMap.Handle;
end;

调用代码:
procedure TForm1.Button1Click(Sender: TObject);
begin
Image1.Picture.Bitmap.Handle:=Fobject.MyimageHandle;
end;

解决方案如此简单,简单的不能接受,哈哈。
在此要感谢unsigned ,不得闲的热心帮助。最终是不得闲的思路让我考虑这个问题从复杂回归到简单。
不得闲 2008-10-29
  • 打赏
  • 举报
回复
传递句柄,然后接受方使用偶的函数,还原成你要的数据信息就OK
僵哥 2008-10-29
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 aniugee 的回复:]
Delphi(Pascal) code
Itestimage = interface(IDispatch)
['{DBE43759-A55C-4B11-951D-A5466BC0642D}']
function Get_image: IPictureDisp; safecall;
procedure Set_image(const Value: IPictureDisp); safecall;
property image: IPictureDisp read Get_image write Set_image;

function Ttestimage.Get_image: IPictureDisp;
var
picture:Tpicture;
BitMap:TBitMap;
var
DeskWnd, Des…
[/Quote]
在对端有没有从IPictureDisp到TPicture的还原?
不得闲 2008-10-29
  • 打赏
  • 举报
回复
procedure SaveHBmpToStream(const bmpHandle: HBITMAP;Stream: TStream);
var
ds: TDIBSection;
BmpFileHeader: TBitmapFileHeader;
NumberOfColors,BitCount: Integer;
Bm: tagBITMAP;
Bytes: integer;
begin
if Stream = nil then
raise Exception.Create('Stream无效');
Stream.Size := 0;
Bytes := GetObject(bmpHandle,SizeOf(ds),@ds); //获得有关DIBSECTION结构中的点阵图资讯
if Bytes = 0 then
raise Exception.Create('无效的位图文件');
Bytes := GetObject(bmpHandle,SizeOf(bm),@Bm);//获得tagBITMAP结构
if Bytes = 0 then
raise Exception.Create('无效的位图文件');
try
NumberOfColors := ds.dsBmih.biClrUsed;//获得调色板中实际使用的颜色数
BitCount := ds.dsBmih.biBitCount;//位图位数
if (NumberOfColors = 0) and (BitCount <= 8) then
NumberOfColors := 1 shl BitCount;
With BmpFileHeader do
begin
bfType := $4D42; // 'BM'位图标记
bfReserved1 := 0;
bfReserved2 := 0;
bfOffBits := SizeOf(TBitmapFileHeader) +
SizeOf(TBitmapInfoHeader) +
NumberOfColors*SizeOf(TRGBQuad); //获得信息头大小
bfSize := bfOffBits + ds.dsBmih.biSizeImage; //获得文件大小
end;
Stream.Write(BmpFileHeader,sizeof(BITMAPFILEHEADER));
Stream.Write(ds.dsBmih,sizeof(TBITMAPINFOHEADER));
stream.Write(Bm.bmBits^, ds.dsBmih.biSizeImage);
Stream.Seek(0,soFromBeginning);
TStream);成功');
except
on E: Exception do
MessageBox(application.Handle,PChar(E.Message),'错误',16);
end;
end;


是转换成流的,就是数据提取,然后写,自己形成位图格式了。
不得闲 2008-10-29
  • 打赏
  • 举报
回复
传递HBitmap句柄过去吧!
然后通过该句柄就可以还原成位图了
给你一个函数做参考!不过是我写的转换成流的
procedure SaveHBmpToStream(const bmpHandle: HBITMAP;Stream: TStream);
var
ds: TDIBSection;
BmpFileHeader: TBitmapFileHeader;
NumberOfColors,BitCount: Integer;
Bm: tagBITMAP;
Bytes: integer;
begin
if Stream = nil then
raise Exception.Create('Stream无效');
Stream.Size := 0;
Bytes := GetObject(bmpHandle,SizeOf(ds),@ds); //获得有关DIBSECTION结构中的点阵图资讯
if Bytes = 0 then
raise Exception.Create('无效的位图文件');
Bytes := GetObject(bmpHandle,SizeOf(bm),@Bm);//获得tagBITMAP结构
if Bytes = 0 then
raise Exception.Create('无效的位图文件');
try
NumberOfColors := ds.dsBmih.biClrUsed;//获得调色板中实际使用的颜色数
BitCount := ds.dsBmih.biBitCount;//位图位数
if (NumberOfColors = 0) and (BitCount <= 8) then
NumberOfColors := 1 shl BitCount;
With BmpFileHeader do
begin
bfType := $4D42; // 'BM'位图标记
bfReserved1 := 0;
bfReserved2 := 0;
bfOffBits := SizeOf(TBitmapFileHeader) +
SizeOf(TBitmapInfoHeader) +
NumberOfColors*SizeOf(TRGBQuad); //获得信息头大小
bfSize := bfOffBits + ds.dsBmih.biSizeImage; //获得文件大小
end;
Stream.Write(BmpFileHeader,sizeof(BITMAPFILEHEADER));
Stream.Write(ds.dsBmih,sizeof(TBITMAPINFOHEADER));
stream.Write(Bm.bmBits^, ds.dsBmih.biSizeImage);
Stream.Seek(0,soFromBeginning);
Ini.WriteString('成功','SaveHBmpToStream','调用procedure SaveHBmpToStream(const bmpHandle: HBITMAP;Stream: TStream);成功');
except
on E: Exception do
MessageBox(application.Handle,PChar(E.Message),'错误',16);
end;
end;
aniugee 2008-10-29
  • 打赏
  • 举报
回复
com中的参数类型,我能找到的最接近的有两种Ipicture*,picture*
但选中后,在TestIntf_TLB自动生成的代码还是IPictureDisp
    
function Get_Myimage: IPictureDisp; safecall;
procedure Set_Myimage(const Value: IPictureDisp); safecall;
property Myimage: IPictureDisp read Get_Myimage write Set_Myimage;

上面的代码,明明我选的是picture*类型,晕倒...
fangsp 2008-10-29
  • 打赏
  • 举报
回复
用 IPicture 来试一下
僵哥 2008-10-29
  • 打赏
  • 举报
回复
那你就不能使用IPictureDisp,而应该用IPicture.
aniugee 2008-10-29
  • 打赏
  • 举报
回复
其实我想要的效果很简单,就是把com中的TBitmap参数传给调用者,同时要考虑每秒15帧以上的频率。
aniugee 2008-10-29
  • 打赏
  • 举报
回复

Itestimage = interface(IDispatch)
['{DBE43759-A55C-4B11-951D-A5466BC0642D}']
function Get_image: IPictureDisp; safecall;
procedure Set_image(const Value: IPictureDisp); safecall;
property image: IPictureDisp read Get_image write Set_image;

function Ttestimage.Get_image: IPictureDisp;
var
picture:Tpicture;
BitMap:TBitMap;
var
DeskWnd, DeskDC:LongWord;
begin
picture:=Tpicture.Create;
DeskWnd:=GetDesktopWindow();
DeskDC:=GetDC(DeskWnd);
BitMap:=TBitMap.Create;
try
BitMap.Width:=Screen.Width;
BitMap.Height:=Screen.Height;
Bitblt(BitMap.Canvas.Handle,0,0,Screen.Width,Screen.Height,
DeskDC,0,0,SRCCOPY);
Picture.Assign(Bitmap);
GetOlePicture(Picture,Result);//
finally
ReleaseDC(DeskWnd,DeskDC);
picture.Free;
end;
end;


调用

procedure TForm1.Button1Click(Sender: TObject);
begin
SetOlePicture(Image1.Picture,Fobject.image);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Fobject:= CreateComObject(CLASS_testimage) as ItestimageDisp;
end;

运行时不出错,但是图片出不来,而且在执行
SetOlePicture(Image1.Picture,Fobject.image);
这句时,会弹出cpu调式的单元

7C92120F C3 ret
7C921210 8BFF mov edi,edi
ntdll.DbgUserBreakPoint:
7C921212 CC int 3
7C921213 C3 ret
7C921214 8BFF mov edi,edi
7C921216 8B442404 mov eax,[esp+$04]
7C92121A CC int 3
7C92121B C20400 ret $0004
ntdll.NtCurrentTeb:
7C92121E 64A118000000 mov eax, fs:[$00000018]
.....略

当然在这一句之前Picture.Assign(Bitmap)我能确定这个图是有的,因为我用ole转换成流的方式传递图片,调用者能显示出来,只是我认为用Ole转换成流(发送和接需要jpeg压缩,不用jpeg压缩image加载图片会失败),比较占用资源(因为我要传输的可是视频数据,每秒不低于15帧),不可取。
僵哥 2008-10-28
  • 打赏
  • 举报
回复
Uses
AxCtrls;

var
bmp: TBitmap;
Picture:TPicture;
PictureAdapter :TPictureAdapter;

MyPicDisp:IPictureDisp;

begin
bmp := TBitmap.Create;
try
bmp.LoadFromFile(FileName);//当然也可以直接由TPicture来Load
Picture := TPicture.Create;
try
Picture.Assign(bmp);
GetOlePicture(Picture,MyPicDisp);//这里由TPicture得到IPictureDisp
finally
Picture.Free;
end;
finally
bmp.Free;
end;
end;
僵哥 2008-10-28
  • 打赏
  • 举报
回复
关键要看你如何传,你也可以用字节数据传.
IPictureDisp是一个Dispatch,适用于远程操作,而不是传输.

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧