天马阁

 找回密码
 立即注册
                                        →→→→→→→→→→→→ 1点击查看所有VIP教程目录长列表(总教程数269个) 2办理VIP详情进入 ←←←←←←←←←←←←
1 x64CE与x64dbg入门基础教程 7课 已完结 2 x64汇编语言基础教程 16课 已完结 3 x64辅助入门基础教程 9课 已完结 4 C++x64内存辅助实战技术教程 149课 已完结
5 C++x64内存检测与过检测技术教程 10课 已完结 6 C+x64二叉树分析遍历与LUA自动登陆教程 19课已完结 7 C++BT功能原理与x64实战教程 29课 已完结 8 C+FPS框透视与自瞄x64实现原理及防护思路 30课完结
64驱?封? 9 64反驱? 10 64位V? 11 绝? 12 ???课?
13 64透 ? 14 64U ? 15 64Q ? 16 64功 ?
17 64U ? 18 64模 ? 19 64多 ? 20 64网 ?
21 64注 ? 22 64火 ? 23 64棋 ? 24 64自二链L?
25 64破 ? VIP会员办理QQ: 89986068   
【请先加好友,然后到好友列表双击联系客服办理,不然可能无法接受到信息。】
27 加入2000人交流群637034024 3 28 免责声明?
查看: 1103|回复: 0

在VC++中基于dll开发插件用于各种图片显示(BMP/TGA/JPG/GIF/PNG/T...

[复制链接]

15

主题

0

回帖

18

积分

编程入门

Rank: 1

天马币
30
发表于 2024-3-1 14:04:32 | 显示全部楼层 |阅读模式
一、图片显示
图片显示的方法:
1.  直接写程序
2.  第3方库
3.  调用COM组件的IPicture接口
4.  使用MFC的CPictureHolder类
5.  使用GDI+的CImage类(VC6无,从VS2003开始有)
测试过的方法有1、3、5。
测试过的格式有BMP/TGA/JPG/GIF/PNG/TIF/ICO/WMF/EMF。
IPicture接口不支持的格式有:PNG和TIF。
GDI+支持全部格式。


二、插件的实现(VC6)
只做了基于DLL的插件实现试验,基于“公共契约”来实现。
基本方法:
① 使插件和主程序实现相同的公共基类。
② 插件只通过公共基类方法与主程序联系,公共基类方法一般为虚函数。
③ 主程序通过指向公共基类的指针数组保存插件访问地址列表。
④ 主程序根据功能需要遍历插件访问地址列表,通过地址访问插件方法。
下面以图像显示为例说明插件的实现过程:

1个主程序Host,4个插件(分别实现对BMP、TGA、JPG、PNG图片的解析)

1.公共基类
// IImageParser is the interface that all image parsers must implement
class IImageParser
{
public:
     virtual const char * GetID() = 0; // content to be present in host
     // parses the image file and reads it into a HBITMAP
     virtual HBITMAP ParseFile( const char *fname ) = 0;
     // returns true if the file type is supported
     virtual bool SupportsType( const char *type ) const = 0;
};


2.插件实现
以BMP Parser为例:
① BMPParser.h内容如下:
#include <windows.h>
#include <stdio.h>
#include "ImageParser.h"
class CBMPParser : public IImageParser  
{
public:
     CBMPParser();
     virtual ~CBMPParser();
public:
     virtual const char * GetID() { return "BMP";};
     virtual HBITMAP ParseFile( const char *fname );
     virtual bool SupportsType( const char *type ) const;
     
private:
     HBITMAP CreateBitmap( int width, int height, void **data );
};
static CBMPParser g_BMPParser;
② BMPParser.cpp的主要内容如下:
// Creates a bitmap with the specified size
HBITMAP CBMPParser::CreateBitmap( int width, int height, void **data )
{
     BITMAPINFO bmi={sizeof(BITMAPINFOHEADER),width,height,1,24,0,0,0,0,0,0};
     return CreateDIBSection(NULL,&bmi,DIB_RGB_COLORS,data,0,0);
}
// Parses a BMP file
HBITMAP CBMPParser:arseFile( const char *fname )
{
     FILE *f=fopen(fname,"rb");
     if (!f) return NULL;
     
     BITMAPFILEHEADER bmfh;
     memset(&bmfh,0,sizeof(bmfh));
     fread(&bmfh,sizeof(bmfh),1,f);
     BITMAPINFOHEADER bmih;
     memset(&bmih,0,sizeof(bmih));
     fread(&bmih,sizeof(bmih),1,f);
     int width=bmih.biWidth;
     int height=bmih.biHeight;
     
     if (bmih.biBitCount!=24) {
         // only 24 bit images are supported
         fclose(f);
         return NULL;
     }
     
     // create the HBITMAP
     void *data;
     HBITMAP bitmap=CreateBitmap(width,height,&data);
     if (!bitmap) {
         fclose(f);
         return NULL;
     }
     
     // read the pixels
     int pitch=(width*3+3)&~3;
     fread(data,pitch,height,f);
     
     fclose(f);
     return bitmap;
}
// Notifies the host that the plugin supports the BMP type
bool CBMPParser::SupportsType( const char *type ) const
{
     return stricmp(type,".bmp")==0;
}
// The host calls this function to get access to the image parser
extern "C" __declspec(dllexport) IImageParser *GetParser( void ) { return &g_BMPParser; }

③ 工作机制
Host通过方法查询该插件是否支持“某种格式”,如果支持,而调用方法对图片数据进行解析。解析的结果是包含图像像素数据的HBITMAP对象。如果该插件不支持该格式,则继续查询下一插件。

2.主程序Host的实现
实验采用标准的MFC架构。

① 实现插件管理类
const int MAX_PARSERS=100;
#include <windows.h>
#include <stdio.h>
#include "ImageParser.h"
class CImageManager  
{   
public:
   CImageManager();
    virtual ~CImageManager();
private:
    // a prototype for the GetParser function
    typedef IImageParser *(*TGetParser)( void );
     
    // a global list with all parsers
    IImageParser *g_Parsers[MAX_PARSERS];
    int g_NumParsers;
     
public:
    // the currently displayed bitmap
    HBITMAP g_Bitmap;
public:
    // Adds the parser to the g_Parsers list
    void AddParser( IImageParser *parser );
    // Loads all plugins in the same folder as the EXE
    void LoadPlugins( CMenu * menu );
     
    // Loads an image file
    BOOL LoadImage( const char *fname );
};

② 应用程序类CHostApp中定义图像插件管理类
CImageManager* m_imgManager;

③ 框架类CMainFrame中加载插件并实现图片文件拖放
OnCreate()方法中:
((CHostApp*)AfxGetApp())->m_imgManager->LoadPlugins(GetMenu()); //加载插件
DragAcceptFiles(TRUE); //允许拖放
OnDropFiles()响应函数中:
// get the file name
char fname[_MAX_PATH];
DragQueryFile(hDropInfo,0,fname,_MAX_PATH);
DragFinish(hDropInfo);
// load the image file
((CHostApp*)AfxGetApp())->m_imgManager->LoadImage(fname);
CRect rect;
GetClientRect(&rect);
InvalidateRect(rect, TRUE);

④ 文档类CHostDoc中OnOpenDocument()方法打开图像,并通过插件类进行加载
((CHostApp*)AfxGetApp())->m_imgManager->LoadImage(lpszPathName);

⑤ 视图类CHostView中OnDraw()方法显示图像
CImageManager* imgManager = ((CHostApp*)AfxGetApp())->m_imgManager;
if (NULL != imgManager && NULL != imgManager->g_Bitmap)
{
     HBITMAP oldBitmap;
     BITMAP bmp;
     CDC memDC;
     CRect rect;
     memDC.CreateCompatibleDC(pDC);
     GetClientRect(&rect);
     oldBitmap = (HBITMAP)memDC.SelectObject(imgManager->g_Bitmap);
     GetObject(imgManager->g_Bitmap, sizeof(bmp), &bmp);
     pDC->BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, &memDC, 0, 0, SRCCOPY);
     memDC.SelectObject(oldBitmap);
     memDC.DeleteDC();
}
完毕!


三、IPicture接口解析图像文件
参见《利用COM组件IPicture读取jpg、gif、bmp图片文件数据和显示图片的两个函数》:
显示图片格式的程序中只需要解析到HBITMAP为止,修改后的函数如下:
HBITMAP CJPGParser:arseFile( const char *pName )
{
    HDC            hdcTemp; //DC用来保存位图  
    HBITMAP     hbmpTemp;   // 保存临时位图  
    IPicture    *pPicture;  // 定义IPicture Interface  
    OLECHAR     wszPath[MAX_PATH+1]; // 图片的完全路径  
    char        szPath[MAX_PATH+1];  // 图片的完全路径  
    long        lWidth; // 图像宽度  
    long        lHeight;    // 图像高度  
    long        lWidthPixels;    // 图像的宽带(以像素为单位)  
    long        lHeightPixels;   // 图像的高带(以像素为单位)  
     strcpy(szPath, pName);  // 把路径拷贝到 szPath
    // 把ASCII码转化为Unicode标准码  
    MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
    HRESULT hr = OleLoadPicturePath(wszPath, 0, 0, 0, IID_IPicture, (void**)&pPicture);  
    if(FAILED(hr))  // 如果导入失败  
    {  
        MessageBox (HWND_DESKTOP, "图片导入失败!/n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);  
        return NULL;
    }  
    hdcTemp = CreateCompatibleDC(GetDC(NULL)); // 建立窗口设备描述表  
    if(!hdcTemp)    // 建立失败?  
    {  
        pPicture->Release(); // 释放IPicture  
        MessageBox (HWND_DESKTOP, "图片导入失败!/n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);  
        return NULL;
    }  
    pPicture->get_Width(&lWidth);    // 取得IPicture 宽度 (转换为Pixels格式)  
    lWidthPixels = MulDiv(lWidth, GetDeviceCaps(hdcTemp, LOGPIXELSX), 2540);  
    pPicture->get_Height(&lHeight);  // 取得IPicture 高度 (转换为Pixels格式)  
    lHeightPixels = MulDiv(lHeight, GetDeviceCaps(hdcTemp, LOGPIXELSY), 2540);  
    BITMAPINFO  bi = {0};     // 位图的类型  
     void       *pData = 0; // 指向位图Data的指针  
    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // 设置结构大小  
    bi.bmiHeader.biBitCount = 32;                // 32 位  
    bi.bmiHeader.biWidth    = lWidthPixels; // 宽度像素值  
    bi.bmiHeader.biHeight   = lHeightPixels;    // 高度像素值  
    bi.bmiHeader.biCompression  = BI_RGB;            // RGB 格式  
    bi.bmiHeader.biPlanes   = 1;                    // 一个位平面  
    // 建立一个位图这样我们可以指定颜色和深度 并访问每位的值  
    hbmpTemp = CreateDIBSection(hdcTemp, &bi, DIB_RGB_COLORS, &pData, 0, 0);  
    if(!hbmpTemp)   // 建立失败?  
    {  
        DeleteDC(hdcTemp);   // 删除设备描述表  
        pPicture->Release();   // 释放IPicture  
        MessageBox (HWND_DESKTOP, "图片导入失败!/n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);  
        return NULL;
    }     
    SelectObject(hdcTemp, hbmpTemp); //选择临时DC句柄和临时位图对象  
    // 在位图上绘制IPicture  
    pPicture->Render(hdcTemp, 0, 0, lWidthPixels, lHeightPixels, 0, lHeight, lWidth, -lHeight, 0);  
    DeleteDC(hdcTemp);  // 删除设备描述表  
    pPicture->Release(); // 释放 IPicture  
     return hbmpTemp;
}
基本原理是建立一个虚拟的HDC,将图绘制到该HDC上即可获得图像像素数据。


四、使用GDI+解析图像文件
VC6不支持GDI+,但可以将VS2003以上版的CImage类通过DLL包括后引入VC6。针对上文的图像显示,包装的方法有两种:

1.只用CImage解析图片文件,返回HBITMAP
参见《VC6 CImage 加载jpg png bmp》
我的基于VS2008的 DLL的实现代码如下:

① Image2008.h中的代码:
#ifndef AFX_EXT_CLASS
#define AFX_EXT_CLASS __declspec(dllimport)
#endif
extern "C" AFX_EXT_CLASS HBITMAP LoadAtlImage(const char * pszFileName);

② Image2008.cpp中的代码:
#define AFX_EXT_CLASS __declspec(dllexport)
#include "stdafx.h"
#include "Image08.h"
#include <atlimage.h>
#include <atlconv.h>
HBITMAP LoadAtlImage(const char * pszFileName)
{
     CImage img;
     USES_CONVERSION;
     HRESULT hr = img.Load(A2T(pszFileName));
     if (SUCCEEDED(hr))
         return img.Detach();
     else
         return NULL;
}


③ 图片文件解析过程
typedef HBITMAP (*LoadImageFunc)(const char *);
LoadImageFunc funcLoadImage = NULL;
HBITMAP hBitmap = NULL;
char szPath[_MAX_PATH];
GetModuleFileName(NULL,szPath,_MAX_PATH);
*PathFindFileName(szPath) = 0;
strcat(szPath, "//CImage08.dll");
HMODULE hModule=LoadLibrary(szPath);
if(hModule)
{
     funcLoadImage = (LoadImageFunc)GetProcAddress(hModule, "LoadAtlImage");
     if (funcLoadImage)
         hBitmap = funcLoadImage(pName);
     FreeLibrary(hModule);
}
return hBitmap;

2.逐函数包括CImage
参见《VC6如何使用VS2005中的CImage类功能》
我的基于VS2008的 DLL的实现代码如下:

① Image2008.h中的代码:
#ifndef AFX_EXT_CLASS
#define AFX_EXT_CLASS __declspec(dllimport)
#endif
class AFX_EXT_CLASS CImage08
{
private:
     void * m_pImage;   //内部数据
public:
     CImage08(void);
     virtual ~CImage08(void);
public:
     inline HRESULT Load(LPCSTR pszFileName);  //装载图片
     inline BOOL IsNull();  //资源是否存在
     inline BOOL Draw(HDC hDestDC, const RECT& rectDest);    //指定设备和区域画图
     inline operator HBITMAP();  //转换为GDI中的HBITMAP, 从而供GDI中的CDC等类使用
};

② Image2008.cpp中的代码:
#define AFX_EXT_CLASS __declspec(dllexport)
#include "stdafx.h"
#include "Image08.h"
#include <atlimage.h>
#include <atlconv.h>
CImage08::CImage08(void)
{
     m_pImage=NULL;
     m_pImage=new CImage;
}
CImage08::~CImage08(void)
{
     if(m_pImage)
     {
         delete m_pImage;
         m_pImage=NULL;
     }
}
inline HRESULT CImage08:oad( LPCSTR pszFileName )
{
     USES_CONVERSION;
     return ((CImage*)m_pImage)->Load(A2T(pszFileName));
}
inline BOOL CImage08::IsNull()
{
     return ((CImage*)m_pImage)->IsNull();
}
inline BOOL CImage08:raw( HDC hDestDC, const RECT& rectDest )
{
     return ((CImage*)m_pImage)->Draw(hDestDC,rectDest );
}
inline  CImage08:perator HBITMAP()
{
     return ((CImage*)m_pImage)->operator HBITMAP();
}
使用方法与普通的DLL无异,将编译后的.dll文件、.lib文件、.h文件引入Host主程序即可

③ 图片文件解析过程
CImage08 img;
HRESULT rtl = img.Load(pName);
if (rtl == S_OK)
     return img;
else
     return NULL;

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

天马阁|C/C++辅助教程|安卓逆向安全| 论坛导航|免责申明|Archiver||网站地图
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表天马阁立场!
任何人不得以任何方式翻录、盗版或出售本站视频,一经发现我们将追究其相关责任!
我们一直在努力成为最好的编程论坛!
Copyright© 2010-2021 All Right Reserved.
快速回复 返回顶部 返回列表