GDI+显示多帧GIF文件的问题

Sky_huang 2009-01-14 06:06:45
我想用GDI+显示GIF
打开显示都没有问题,但在VS的output窗口中是会出现以下异常提示(但是程序能够正常运行,异常应该是出现在Gdiplus内部):
"Example.exe 中的0x4afdb258 (GdiPlus.dll) 处最可能的异常: 0xC0000005: 写入位置0x01670017 时发生访问冲突"
我试着用WinDbg调试了一下,但因对调试方法掌握有限,找不出问题根源所在,还望高手指点一二
以下是相关源码和WinDbg中的信息以及异常发生时的call stack
(为了例子简单点,就用C#写了,运行结果与VC中是一样的,每次点击Button1时显示下一帧)
Image image = Image.FromFile("c:\\a1.gif");
int idx = 0;

private void button1_Click(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();

Point p = new Point(20, 20);
g.DrawImage(image, p);
g.Dispose();
idx++;

System.Drawing.Imaging.FrameDimension fd = new
System.Drawing.Imaging.FrameDimension(image.FrameDimensionsList[0]);

if (idx >= image.GetFrameCount(fd)) idx = 0;

image.SelectActiveFrame(fd, idx);
}

// WinDbg call stack
gdiplus!LZWDecompressor::FHandleNext+0x10a
gdiplus!GpGifCodec::ProcessImageChunk+0x935
gdiplus!GpGifCodec::DoDecode+0x1d6
gdiplus!GpGifCodec::Decode+0x91
gdiplus!GpDecodedImage::InternalPushIntoSink+0x2e
gdiplus!GpDecodedImage::PushIntoSink+0x2e
gdiplus!GpMemoryBitmap::InitImageBitmap+0xcc
gdiplus!GpMemoryBitmap::CreateFromImage+0x49
gdiplus!CopyOnWriteBitmap::SelectActiveFrame+0xa7
gdiplus!GpBitmap::SelectActiveFrame+0x22
gdiplus!GdipImageSelectActiveFrame+0x61

// the result in Command window
CommandLine: C:\WindowsApplication1.exe
Symbol search path is:
srv*D:\Symbols\*http://msdl.microsoft.com/download/symbols
Executable search path is:
ModLoad: 00400000 00408000 WindowsApplication1.exe
ModLoad: 7c920000 7c9b4000 ntdll.dll
ModLoad: 79000000 79045000 C:\WINDOWS\system32\mscoree.dll
ModLoad: 7c800000 7c91d000 C:\WINDOWS\system32\KERNEL32.dll
(adc.b0c): Break instruction exception - code 80000003 (first chance)
eax=00241eb4 ebx=7ffdd000 ecx=00000001 edx=00000002 esi=00241f48
edi=00241eb4
eip=7c921230 esp=0012fb20 ebp=0012fc94 iopl=0 nv up ei pl nz na po
nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000
efl=00000202
ntdll!DbgBreakPoint:
7c921230 cc int 3
0:000> g
ModLoad: 77da0000 77e49000 C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 77e50000 77ee2000 C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 77fc0000 77fd1000 C:\WINDOWS\system32\Secur32.dll
ModLoad: 77f40000 77fb6000 C:\WINDOWS\system32\SHLWAPI.dll
ModLoad: 77ef0000 77f38000 C:\WINDOWS\system32\GDI32.dll
ModLoad: 77d10000 77d9f000 C:\WINDOWS\system32\USER32.dll
ModLoad: 77be0000 77c38000 C:\WINDOWS\system32\msvcrt.dll
ModLoad: 76300000 7631d000 C:\WINDOWS\system32\IMM32.DLL
ModLoad: 62c20000 62c29000 C:\WINDOWS\system32\LPK.DLL
ModLoad: 73fa0000 7400b000 C:\WINDOWS\system32\USP10.dll
ModLoad: 79e70000 7a3d1000
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
ModLoad: 78130000 781cb000
C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.762_x-ww_6b128700\MSVCR80.dll
ModLoad: 7d590000 7dd83000 C:\WINDOWS\system32\shell32.dll
ModLoad: 77180000 77283000
C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2982_x-ww_ac3f9c03\comctl32.dll
ModLoad: 5d170000 5d20a000 C:\WINDOWS\system32\comctl32.dll
ModLoad: 60340000 60348000
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\culture.dll
ModLoad: 790c0000 79ba8000
C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\05ea9a15deafba439c2310d567c238a3\mscorlib.ni.dll
ModLoad: 76990000 76acd000 C:\WINDOWS\system32\ole32.dll
ModLoad: 5adc0000 5adf7000 C:\WINDOWS\system32\uxtheme.dll
ModLoad: 74680000 746cb000 C:\WINDOWS\system32\MSCTF.dll
ModLoad: 79060000 790b3000
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorjit.dll
ModLoad: 7a440000 7abfe000
C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System\5e097525f7cde84189d11ca01edb7c8a\System.ni.dll
ModLoad: 7ade0000 7af74000
C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Drawing\29b91bd046189a43b459360fd79e49d5\System.Drawing.ni.dll
ModLoad: 7afd0000 7bc56000
C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Windows.Forms\2583b8a9aad76047a5097c79156a341f\System.Windows.Forms.ni.dll
ModLoad: 4ec50000 4edf6000
C:\WINDOWS\WinSxS\x86_Microsoft.Windows.GdiPlus_6595b64144ccf1df_1.0.2600.5581_x-ww_dfbc4fc4\gdiplus.dll
ModLoad: 77bd0000 77bd8000 C:\WINDOWS\system32\version.dll
ModLoad: 73640000 7366e000 C:\WINDOWS\system32\msctfime.ime
(adc.b0c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00203930 ebx=00000002 ecx=01200001 edx=00203930 esi=00f054f0
edi=00000002
eip=4ed9b280 esp=0012eafc ebp=0012eb24 iopl=0 nv up ei pl nz na po
nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000
efl=00010202
gdiplus!LZWDecompressor::FHandleNext+0x10a:
4ed9b280 8801 mov byte ptr [ecx],al
ds:0023:01200001=??

难道是GDI+对GIF的LZW解码出了问题?如果是,又要怎么解决呢?
...全文
1215 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
Sky_huang 2009-06-24
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 wuwenxi 的回复:]
gdi+要进行初始化过才能用的
[/Quote]

都已经上图了,怎么可能没有初始化,本贴到此为止了,暂时不再考虑使用GDI+
wuwenxi 2009-06-16
  • 打赏
  • 举报
回复
gdi+要进行初始化过才能用的
Sky_huang 2009-05-23
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 crybird 的回复:]
你的问题解决了吗
我碰到了和你一样的情况
当调用SelectActiveFrame的时候,就会发生错误
GifTestDlg.exe 中的 0x4afdb280 处最可能的异常: 0xC0000005: 写入位置 0x01470001 时发生访问冲突
好像是写什么的时候,指针为NULL或非正常 报错是在GDI+内部
继续等达人
[/Quote]

不好意思,很久没上CSDN了,后来改了机制,没再用GDI+来实现了,因为GDI+跟系统的偶合性太强了,很多方面都无法控制,后来根据CPictureEx进行了修改,封装了一个解码GIF的类并加入到组件中,你可以参考,Google一下CPictureEx,是一个开源的东东
  • 打赏
  • 举报
回复
你的问题解决了吗
我碰到了和你一样的情况
当调用SelectActiveFrame的时候,就会发生错误
GifTestDlg.exe 中的 0x4afdb280 处最可能的异常: 0xC0000005: 写入位置 0x01470001 时发生访问冲突
好像是写什么的时候,指针为NULL或非正常 报错是在GDI+内部
继续等达人
龙凤呈祥焱 2009-02-03
  • 打赏
  • 举报
回复
异常本身可是被认为是一种错误,同时也可以用来做一些事务处理.特别是结构化异常处理.
MS内部的API很多都利用了异常来做特殊处理.GDI+只是其中一个.
最常用的C库的strcpy不能处理空指针.但MS的lstrcpyW(A)就可以.因为内部有结构化异常.
GDI+显示GIF出现FIRST CHANCE是正常的.
Show_Mike 2009-02-03
  • 打赏
  • 举报
回复
哦,不好意思,我可能把回答别人的帖子贴到你这里来了.
你的问题,认真看了一下,觉得不是你的代码问题,当然也并不是gdiplus不能对lzw正常解码以及上面显示出来的许多编解码的函数.
你的调试提示也表明这些异常是可以预见和处理的.实际上,相当于一种"警告".当然,如果从程序设计上来说,发现这些异常并从逻辑上回避它是提高程序质量的重要途径.
bobbygao18 2009-02-03
  • 打赏
  • 举报
回复
To Show_Mike
这似乎不是警告,FIRST CHANCE EXCEPTION是系统扔的,你可以设置让DEBUGER在那个异常处(DEBUGING-》EXCEPTION-》WIN32 NATIVE)BREAK,如果任由系统抛异常的话,这是对性能最大的影响。。。。。
bobbygao18 2009-02-03
  • 打赏
  • 举报
回复
PS。。我同样是用GDI显示GIF的问题,只要一调用DRAWIMAGE就抛异常。。但是显示正常。。。和你基本一样。。。不知道这是不是MS GDI的又一个feature呢。。
bobbygao18 2009-02-03
  • 打赏
  • 举报
回复
哥们我遇到了同样的问题。。一摸一样。。。程序运行正常,就是不停的抛ACCESS VIOLIATION 异常。。疯了。。google了一通仍然找不到答案。。。有高人解答么?
Sky_huang 2009-01-19
  • 打赏
  • 举报
回复
对11楼的回复补充一点:
我上面所说的方法应该只适用于进程内,如果是进程间的复制,那你还得考虑stream或者ole clipboard了
Sky_huang 2009-01-19
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 Show_Mike 的回复:]
提一个问题:这应该十一个界面设计的问题,显示多帧图像(例如,可以参考image2ani),那么,如果打算封装为控件,建议图像允许格式应该更多一些,如包括jpeg,bmp,png等等
[/Quote]
没明白你的意思,你是要问问题,还是给我的问题提建议?
如果你是要一个能够显示jpeg,bmp,WMF,ico,cur等格式的控件,那CPictureExWnd就是一个不错的选择,稍微改一下就行了,PNG和TIFF没试过,你可做个试验,如果不行,那也可以考虑使用GDI+,用GDI+来实现蛮简单的,只是我在使用时遇到了我之前所提及的问题,你可以避免使用GDI+来显示GIF,当然,即使用GDI+来显示多帧GIF似乎也没有致命的错误
Sky_huang 2009-01-19
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 terran_ye 的回复:]
我在网上下载了个CPictureex的类。改装了一下,来显示GIF。不会出现你说的效果。

另外,我问个问题。你需要将一个Richedit里面的内容复制到令一个Richedit里面去吗?

有用Richedit的StreamOut?
[/Quote]

CPictureEx我也看了,用IPicture来实现的,大致看了一下并试着运行了,似乎没有问题,只是它那个使用线程的机制不行,还得改改才能用,之所以选择GDI Plus,是因为实现起来要简单得多,而且对TIFF的支持也比较好

至于你说的RichEdit中的内容复制到另一个RichEdit中,方法很多,当然,使用StreamOut也是可以的,也可以使用Ole剪贴板,处理一下IRichEditOleCallback就行了,当然还得使用一些机制来维护Ole剪贴板

对于你在9楼中的问题,我没有遇到过,我想你要实现的目标应该类似于即时通讯工具在发送消息时,将发送窗口(reSource)中的内容显示到消息历史记录窗口(reTarget)中,我想只要能够实现Ole对象的复制其它都好解决了,大致步骤如下:
1. 记录目标RichEdit当前长度(如果你是整个RichEdit复制那这步就是多余的了)
2. 复制源RichEdit中的文本内容到目标RichEdit,这个就不用说具体怎么做了,只要文本内容
3. 遍历源RichEdit,将所有Ole对象复制到目标RichEdit中,参见后面的示例
4. 其它处理,如果是类似QQ之类的功能,那还得进行网络发送以及清除输入框中的内容等

// step 1
int last_pos = reTarget->GetTextLen();
// step 2
// ...
// step 3
int ObjectCount = preoSource->GetObjectCount();
REOBJECT reobject;
for (int i = 0; i < ObjectCount; i++)
{
ZeroMemory(&reobject, sizeof(REOBJECT));
reobject.cbStruct = sizeof(REOBJECT);

preoSource->GetObject(i, &reobject, REO_GETOBJ_ALL_INTERFACES);

reTarget->SelStart = last_pos+reobject.cp;

CopyOleObject(preoTarget, &reobject);
}

void CopyOleObject(IRichEditOle* preOle, REOBJECT* lpreobject)
{
IOleClientSite* pOleClientSite;
preOle->GetClientSite(&pOleClientSite);

lpreobject->cp = REO_CP_SELECTION;
lpreobject->dvaspect = DVASPECT_CONTENT;
lpreobject->polesite = pOleClientSite;

preOle->InsertObject(lpreobject);

pOleClientSite->Release();
}
// step 4
// ...
// 这样做理论上应该是行得通的,至于性能,你可与使用StreamOut的情况对比一下,可能会差一点,但是如果内容不多,影响不大,希望能够对你有所帮助!
Show_Mike 2009-01-17
  • 打赏
  • 举报
回复
提一个问题:这应该十一个界面设计的问题,显示多帧图像(例如,可以参考image2ani),那么,如果打算封装为控件,建议图像允许格式应该更多一些,如包括jpeg,bmp,png等等
terran_ye 2009-01-17
  • 打赏
  • 举报
回复
有没有出现StreamOut出来的数据变的很大的情况? 比如你插入的GIF图片只有140K的,StreamOut得到的数据有快8M了?

望指点一下
terran_ye 2009-01-17
  • 打赏
  • 举报
回复
我在网上下载了个CPictureex的类。改装了一下,来显示GIF。不会出现你说的效果。

另外,我问个问题。你需要将一个Richedit里面的内容复制到令一个Richedit里面去吗?

有用Richedit的StreamOut?
fanweiliang 2009-01-16
  • 打赏
  • 举报
回复
复杂
Sky_huang 2009-01-16
  • 打赏
  • 举报
回复
没人帮忙看看吗?
Sky_huang 2009-01-16
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 flm007 的回复:]
虽然我看不懂C#语法,但大体看了下,我觉得你DrawImage参数就有问题,你是一个图,怎么能用Point参数呢?
应该用CRect或者坐标!
[/Quote]

这个问题不大,那个Point表示待绘图像的起始位置,即目标区域的左上角位置,因为GDI+封装得比较高,为了方便,做示例程序就用了一个最简单的DrawImage来实现上图了
flm007 2009-01-16
  • 打赏
  • 举报
回复
虽然我看不懂C#语法,但大体看了下,我觉得你DrawImage参数就有问题,你是一个图,怎么能用Point参数呢?
应该用CRect或者坐标!
RockurSoul 2009-01-16
  • 打赏
  • 举报
回复
MS很复杂呢,帮顶
加载更多回复(2)
使用GDI+显示gif动态图片,该类接口如下: 可以看出,该ImageEx完全继承了基类的接口函数。 说明: 如果打开非多图片,该类几乎完全等价于基类,比如你可以把该类的对象代入Graphics类系列的成员函数中; 如果打开的是多的图片,你只要打开图片后不调用InitAnimation函数(它会创建线程),则上述做法依然可以; 但如果调用InitAnimation函数后(单图像没关系,因为不会创建线程),则不可以了, 所有的基类继承过来的接口成员函数和配合gdi+库其他类的函数调用都是不可以的,因为没有作线程同步, 你只能调用下面位数不多的几个public成员函数,调用Destroy成员函数后,则就可以了,因为它会关闭线程。 其实你会发现下面的public成员函数操作的成员变量都是新增的成员变量,没涉及到线程同步问题。 class ImageEx : public Image { public: //以长度为nSize的内存pBuff中的内容构造图像 ImageEx(const void* pBuff, size_t nSize, BOOL useEmbeddedColorManagement = FALSE); //以类型为sResourceType,名称为sResource的资源构造图像 ImageEx(LPCTSTR sResourceType, LPCTSTR sResource, BOOL useEmbeddedColorManagement = FALSE); //以文件构造图像 ImageEx(LPCTSTR filename, BOOL useEmbeddedColorManagement = FALSE); //调用Destroy成员函数 ~ImageEx(); public: //如果已经构造的对象是动画,则创建动画线程,并返回true, //如果为静态图像或已经创建过动画线程,则也返回false // 图像将绘制在m_hWnd客户区的rect区域,会拉伸,支持镜像 bool InitAnimation(HWND hWnd, RECT rect); //判断是否为动画 bool IsAnimatedGIF() { return m_nFrameCount > 1; } //设置动画暂停与否 void SetPause(bool bPause); //判断动画是否处于暂停状态 bool IsPaused() { return m_bPause; } //关闭动画,事实上基类Image中还有的两个成员变量没有关闭,因为析构函数会调用基类析构函数进行关闭的 void Destroy(); //另外的非public的东西省略.. }; 用法: MFC对话框程序在下面添加: BOOL CTestDlgDlg::OnInitDialog() { CDialog::OnInitDialog(); //其它的初始化代码 // GDI+ //m_image为ImageEx指针类型成员变量,"GIF"为资源类型,"HEARTS"为资源名称 m_image = new ImageEx( _T("GIF"), _T("HEARTS") ); RECT rc; GetClientRect(&rc); m_image->InitAnimation(this->m_hWnd, rc);//创建gif播放线程 return TRUE; // return TRUE unless you set the focus to a control } CTestDlgDlg::~CTestDlgDlg() { // GDI+ delete m_image; } 其中的m_image = new ImageEx( _T("GIF"), _T("HEARTS") );你可以换成ImageEx类的另外两个构造函数
保存多Gif图像的程序 压缩包内“CxImageDemo.rar”是源码,“CxImageDemo.exe”是对应的Release版主程序,“截图6.0版.exe”是一个不相关的程序,放在压缩包里的原因在下面给出。 该程序(CxImageDemo.exe)使用VC6,使用CxImage类,UNICODE编译。 具有功能: 1、主打功能为录像屏幕的指定区域并保存为Gif图像; 2、浏览主流图片,但是gif图像不支持动态播放,只显示第一; 3、支持拖放图像文件到界面进行打开; 4、由于程序主打功能是录像指定区域并保存为Gif图像,所以菜单栏的保存和另存为功能没做; 屏幕录像操作过程: 详见程序主界面工具栏最右面的三个小图标tips提示。 值得注意的是,选择的矩形区域支持镜像操作,即如果是从右上角到左下角拉取矩形框,则录制出来的Gif图像会左右翻转;另外保存gif图像是使用的CxImage类,该类保存的Gif彩色图像质量较差且占用内存较大(不关我的事),因此请不要录制太长时间! 录制出来的Gif图像显示效果怎么样?由于该程序没做Gif图像的显示功能(主打功能是录制),因此你可以用附带的另一个“截图6.0版.exe”程序进行打开测试(该程序基于GDI+库,也支持拖放文件进行打开操作,点击鼠标中键自动调整窗口大小)。 如想编译此源码,请确保已配置好CxImage环境。 有问题联系:hastings1986@163.com
保存多Gif图像的程序 前面那个1.0版上传后才发现有一个严重的GDI资源泄漏问题,于是火速上传此1.1版纠正此问题! 压缩包内“CxImageDemo.rar”是源码,“CxImageDemo.exe”是对应的Release版主程序,“截图6.0版.exe”是一个不相关的程序,放在压缩包里的原因在下面给出。 该程序(CxImageDemo.exe)使用VC6,使用CxImage类,UNICODE编译。 具有功能: 1、主打功能为录像屏幕的指定区域并保存为Gif图像; 2、浏览主流图片,但是gif图像不支持动态播放,只显示第一; 3、支持拖放图像文件到界面进行打开; 4、由于程序主打功能是录像指定区域并保存为Gif图像,所以菜单栏的保存和另存为功能没做; 屏幕录像操作过程: 详见程序主界面工具栏最右面的三个小图标tips提示。 值得注意的是,选择的矩形区域支持镜像操作,即如果是从右上角到左下角拉取矩形框,则录制出来的Gif图像会左右翻转;另外保存gif图像是使用的CxImage类,该类保存的Gif彩色图像质量较差且占用内存较大(不关我的事),因此请不要录制太长时间! 录制出来的Gif图像显示效果怎么样?由于该程序没做Gif图像的显示功能(主打功能是录制),因此你可以用附带的另一个“截图6.0版.exe”程序进行打开测试(该程序基于GDI+库,也支持拖放文件进行打开操作,点击鼠标中键自动调整窗口大小)。 如想编译此源码,请确保已配置好CxImage环境。 有问题联系:hastings1986@163.com
保存多Gif图像的程序 此为2.0版,考虑到前面的版本录制时太耗CPU,故此版本把耗时的操作全部一起放在了保存操作中,并且另开线程,防止界面僵死。 压缩包内“CxImageDemo.rar”是源码,“CxImageDemo.exe”是对应的Release版主程序,“截图6.0版.exe”是一个不相关的程序,放在压缩包里的原因在下面给出。 该程序(CxImageDemo.exe)使用VC6,使用CxImage类,UNICODE编译。 具有功能: 1、主打功能为录像屏幕的指定区域并保存为Gif图像; 2、浏览主流图片,但是gif图像不支持动态播放,只显示第一; 3、支持拖放图像文件到界面进行打开; 4、由于程序主打功能是录像,所以菜单栏的保存和另存为功能没做; 屏幕录像操作过程: 详见程序主界面工具栏最右面的三个小图标tips提示。 值得注意的是,选择的矩形区域支持镜像操作,即如果是从右上角到左下角拉取矩形框,则录制出来的Gif图像会左右翻转;另外保存gif图像是使用的CxImage类,该类保存的Gif彩色图像质量较差且占用内存较大(不关我的事),因此请不要录制太长时间,录制时间越长,保存所需时间越长! 录制出来的Gif图像显示效果怎么样?由于该程序没做Gif图像的显示功能(主打功能是录制),因此你可以用附带的另一个“截图6.0版.exe”程序进行打开测试(该程序基于GDI+库,也支持拖放文件进行打开操作,点击鼠标中键自动调整窗口大小)。 如想编译此源码,请确保已配置好CxImage环境。 有问题联系:hastings1986@163.com

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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