关于OLE Server 绘图的问题(100分求助)

powerxun 2016-09-15 09:21:01
最近手头做一个OLE Server的应用程序,基于MFC的Wizard生成。

根据VS的例子,在XXXSrvrItem::OnDraw(CDC* pDC, CSize& rSize)这个函数中进行图形的绘制,
所有的 GDI 函数都没问题。

但由于GDI 的绘图命令比较单一,不能满足要求,所以就考虑使用GDI+,这时候问题出现了,
所有GDI+命令都不起作用!!!

我把这个OLE生成的对象嵌入到WORD 2010中,然后将docx文件解压缩,抽出嵌入的对象,
发现这个OLE生成的对象图片是以WMF的格式存在的。而我按照相同的方式做对比发现,Excel
嵌入在WORD中的对象是以EMF,也即增强型图元存在的!Excel本身也是一种OLE Server。而
显然excel生成的EMF是具有GDI+绘图特性的。

试验了几种方法,包括采用CMateFile::CreateEnhanced等等都不能解决问题,希望能得到各位的帮助!

我在MSDN social,codeproject上都搜索过,但没找到解决方案。ms这个问题比较冷门,或者我搜索
的关键词不对?
...全文
372 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
powerxun 2016-10-02
  • 打赏
  • 举报
回复
引用 4 楼 piaobotudou 的回复:
第3步中的SrvAfxOleCreateDC就是_AfxOleCreateDC重命名一下就好了
这个方法可以!
微型蚂蚁 2016-09-27
  • 打赏
  • 举报
回复
第3步中的SrvAfxOleCreateDC就是_AfxOleCreateDC重命名一下就好了
微型蚂蚁 2016-09-27
  • 打赏
  • 举报
回复
1. 在XXXSrvrItem的构造函数中添加 FORMATETC formatEtc; formatEtc.ptd = NULL; formatEtc.dwAspect = DVASPECT_CONTENT; formatEtc.lindex = -1; // by default, a COleServerItem supports CF_METAFILEPICT formatEtc.cfFormat = CF_ENHMETAFILE; formatEtc.tymed = TYMED_ENHMF; m_dataSource.DelayRenderData(0, &formatEtc); 把默认格式设置为CF_ENHMETAFILE 2. 重写虚函数,参考父类的实现添加EMF支持 virtual BOOL OnRenderData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium) override; BOOL XXXSrvrItem::OnRenderData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium) { ASSERT_VALID(this); ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE)); ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM))); // default implementation does not support extended layout if (lpFormatEtc->lindex != -1) return FALSE; // default implementation supports both types of metafiles if (lpFormatEtc->cfFormat == CF_ENHMETAFILE) return GetEHMetafileData(lpFormatEtc, lpStgMedium); else if (lpFormatEtc->cfFormat == CF_METAFILEPICT) return GetMetafileData(lpFormatEtc, lpStgMedium); return FALSE; // cfFormat not supported } 3. 参考父类GetMetafileData的实现实现EMF绘制 BOOL XXXSrvrItem::GetEHMetafileData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium) { ASSERT_VALID(this); ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE)); ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM))); ASSERT(lpStgMedium->tymed == TYMED_NULL); // GetDataHere not valid ASSERT(lpStgMedium->pUnkForRelease == NULL); // medium must be TYMED_MFPICT -- cannot fill in existing HGLOBAL if (!(lpFormatEtc->tymed & TYMED_ENHMF) || lpStgMedium->hGlobal != NULL) return FALSE; CSize size; if (!OnGetExtent((DVASPECT)lpFormatEtc->dwAspect, size)) { TRACE(traceOle, 0, "Warning: OnGetExtent failed during OnDrawEx --\n"); TRACE(traceOle, 0, "\tpresentation metafile may be badly formed!\n"); } if (size.cy < 0) { TRACE(traceOle, 0, "Warning: HIMETRIC natural size is negative.\n"); size.cy = -size.cy; // backward compatibility fix } CRect bound(0,0,size.cx, size.cy); // create appropriate memory metafile DC CMetaFileDC dc; if (!dc.CreateEnhanced(NULL, 0, &bound, 0)) return FALSE; // create attribute DC according to lpFormatEtc->ptd HDC hAttribDC = SrvAfxOleCreateDC(lpFormatEtc->ptd); if (hAttribDC == NULL) return FALSE; dc.SetAttribDC(hAttribDC); // Paint directly into the metafile. BOOL bResult = OnDrawEx(&dc, (DVASPECT)lpFormatEtc->dwAspect, size); // attribute DC is no longer necessary dc.SetAttribDC(NULL); ::DeleteDC(hAttribDC); if (!bResult) { TRACE(traceOle, 1, "calling COleServerItem::OnDrawEx()failed.\n"); return FALSE; } HENHMETAFILE hMF = dc.CloseEnhanced(); if (hMF == NULL) return FALSE; lpStgMedium->hEnhMetaFile = hMF; lpStgMedium->tymed = TYMED_ENHMF; return TRUE; } 4.其中_AfxOleCreateDC的实现为 HDC WINAPI _AfxOleCreateDC(DVTARGETDEVICE* ptd) { USES_CONVERSION_EX; // return screen DC for NULL target device if (ptd == NULL) return ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL); LPDEVMODEOLE lpDevMode; LPOLESTR lpszDriverName; LPOLESTR lpszDeviceName; LPOLESTR lpszPortName; if (ptd->tdExtDevmodeOffset == 0) lpDevMode = NULL; else lpDevMode = (LPDEVMODEOLE)((LPSTR)ptd + ptd->tdExtDevmodeOffset); lpszDriverName = (LPOLESTR)((BYTE*)ptd + ptd->tdDriverNameOffset); lpszDeviceName = (LPOLESTR)((BYTE*)ptd + ptd->tdDeviceNameOffset); lpszPortName = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset); return ::CreateDC(CString(lpszDriverName), CString(lpszDeviceName), CString(lpszPortName), DEVMODEOLE2T_EX(lpDevMode)); }
powerxun 2016-09-16
  • 打赏
  • 举报
回复
引用 1 楼 zgl7903 的回复:
GdiplusStartup 有没有? 是否成功?
GDI+ 的启动和初始化都做过了,应该不是这个原因。
zgl7903 2016-09-16
  • 打赏
  • 举报
回复
GdiplusStartup 有没有? 是否成功?

15,979

社区成员

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

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