用VC6.0编写Win32程序加载位图(含工程源代码)
2013-01-18 17:25
387 查看
一、实验原理
具体原理,请参考《数字图像处理编程入门》.pdf,呵呵。主要讲的是位图和windows的调色板。考虑到大家估计也没空,我就精简一下,用户代码的形式列出来。如下:
二、上机指导
打开VC++6.0,选择“新建”->“工程”->“win32 application”,然后输入名称,例如xxx,工作区间随意。在向导里面建议选择“一个简单的hello world程序”,点击“完成”。之所以选择简单的hello world 程序,是因为我们可以运行代码并且小范围修改代码,以此来观察win32程序是如何运行的。这里提示一点:
win32程序并不像我们以往学习的C语言一样顺序执行,而是在winproc的消息处理函数里面循环,等待消息触发。大概是这个意思。
三、工程源码
代码我们只需要修改xxx.cpp(即和工程名称相同的那个cpp)即可。该文件完整代码如下,可直接覆盖你的cpp文件。要修改的就是181行的文件路径。
具体原理,请参考《数字图像处理编程入门》.pdf,呵呵。主要讲的是位图和windows的调色板。考虑到大家估计也没空,我就精简一下,用户代码的形式列出来。如下:
/************************************************************************/ 位图文件.bmp文件大体上分为四个部分: 位图文件头BITMAPFILEHEADER 位图信息头BITMAPINFOHEADER 调色板Palette 位图数据ImageData /************************************************************************/ /************************************************************************/ /* WORD 无符号16位整数 DWORD无符号32位整数 */ /************************************************************************/ //BITMAPFILEHEADER //结构长度固定,为14个字节 typedef struct tagBITMFILEHEADER{ WORD bfType; //指定文件类型,必须是0x424D,及字符串“BM” DWORD bfSize; //指定文件大小,包括这14个字节 WORD bfReserved1; //保留字,不予考虑 WORD bfReserved2; //同上 DWORD bfOffBits; //为从文件头到实际的位图数据的皮衣字节数,即位图文件前三个部分长度和 } BITMAPFILEHEADER; //BITMAPINFOHEADER //结构长度固定,为40个字节,其中LONG为32位整数 typedef struct tagBITMAPINFOHEADER{ DWORD biSize; //指定结构长度,为40 LONG biWidth; //指定图像的宽度,单位是像素 LONG biHeight; //高度 WORD biPlanes; //必须为1,不考虑 WORD biBitCount; //指定表示颜色时要用到的位数,常用有1(黑白二色图),24(真彩色图) DWORD biCompression; //指定位图是否压缩,有效值为BI_RGB(不压缩),BI_RLE8等 DWORD biSizeImage; //实际的位图数据占用的字节数 LONG biXPelsPerMeter; //指定目标设备的水平分辨率,单位:每米的像素个数 LONG biYPelsPerMeter; //同上 DWORD biClrUser; //本图像实际用到的颜色数。如果该值为0(即真彩色),颜色数为2^bitBitCount DWORD biClrImportant; //图像中重要的颜色数,如果为0,认为所有颜色都是重要的 }BITMAPINFOHEADER; //Palette 调色板,真彩色图像不需要调色板。 //也称作Look up table //调色板实际上是一个数组(可以查看MSDN),共有biClrUsed个元素(若为0,则有2^bitBitCount个元素)。数组中每个元素的类型都是个 RGBQUAD结构,占4个字节。定义: typedef struct tagRGBQUAD{ BYTE rgbBlue; //该颜色的蓝色分量 BYTE rgbGreen; // BYTE rgbRed; // BYTE rgbReserved; //保留值 }RGBQUAD;
二、上机指导
打开VC++6.0,选择“新建”->“工程”->“win32 application”,然后输入名称,例如xxx,工作区间随意。在向导里面建议选择“一个简单的hello world程序”,点击“完成”。之所以选择简单的hello world 程序,是因为我们可以运行代码并且小范围修改代码,以此来观察win32程序是如何运行的。这里提示一点:
win32程序并不像我们以往学习的C语言一样顺序执行,而是在winproc的消息处理函数里面循环,等待消息触发。大概是这个意思。
三、工程源码
代码我们只需要修改xxx.cpp(即和工程名称相同的那个cpp)即可。该文件完整代码如下,可直接覆盖你的cpp文件。要修改的就是181行的文件路径。
// ImageTemplate.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "resource.h" #include "stdio.h" #define MAX_LOADSTRING 100 //自己加的宏 #define WIDTHBYTES(i) ((i+31)/32*4) // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text //自己的全局变量 BITMAPFILEHEADER bf; BITMAPINFOHEADER bi; HPALETTE hPalette; HBITMAP hBitmap ; HGLOBAL hImgData; // Foward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); BOOL LoadBmpFile(HWND hWnd,char *BmpFileName); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. MSG msg; HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_IMAGETEMPLATE, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_IMAGETEMPLATE); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // // COMMENTS: // // This function and its usage is only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this function // so that the application will get 'well formed' small icons associated // with it. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_IMAGETEMPLATE); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = (LPCSTR)IDC_IMAGETEMPLATE; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex); } // // FUNCTION: InitInstance(HANDLE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) // // PURPOSE: Processes messages for the main window. // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; TCHAR szHello[MAX_LOADSTRING]; // LPSTR szHello = "Fucko"; LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); static HDC hMemDC; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: // hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... // MessageBox(hWnd,"Error alloc memory","Error Message",MB_OK|MB_ICONEXCLAMATION); // // RECT rt; // GetClientRect(hWnd, &rt); // DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER); // EndPaint(hWnd, &ps); // break; hdc = BeginPaint(hWnd,&ps); LoadBmpFile(hWnd,"e:\\xx.bmp");//这里的e:\\xx.bmp是你的位图路径 if (hBitmap) { hMemDC = CreateCompatibleDC(hdc);//建立一个内存设备上下文 if (hPalette)//有调色板 { //将调色板选入屏幕设备上下文 SelectPalette(hdc,hPalette,FALSE); //将调色板选入内存设备上下文 SelectPalette(hMemDC,hPalette,FALSE); RealizePalette(hdc); } //将位图选入内存设备上下文 SelectObject(hMemDC,hBitmap); //显示位图 BitBlt(hdc,0,0,bi.biWidth,bi.biHeight,hMemDC,0,0,SRCCOPY); //释放内存设备上下文 DeleteDC(hMemDC); } //释放屏幕设备上下文 EndPaint(hWnd,&ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // Mesage handler for about box. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } //自己加入的代码 BOOL LoadBmpFile(HWND hWnd,char *BmpFileName) { HFILE hf;// // LPBITMAPINFOHEADER lpImgData; LOGPALETTE *pPal;// LPRGBQUAD lpRGB; HPALETTE hPrevPalette; HDC hDc; HLOCAL hPal; DWORD LineBytes; DWORD ImgSize; // DWORD NumColors; DWORD i; if((hf=_lopen(BmpFileName,OF_READ))==HFILE_ERROR) { MessageBox(hWnd,"File c:\\test.bmp not found!","Error Message", MB_OK|MB_ICONEXCLAMATION); return FALSE; } //将BITMAPFILEHEADER结构从文件中读出,写入bf中 _lread(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER)); // _lread(hf,(LPSTR)&bi,sizeof(BITMAPINFOHEADER)); //需要定义一个宏,因为每行字节数必须为4的倍数 //#define WIDTHBYTES(i) ((i+31)/32*4) //调用WIDTHBYTES(bi.biWidth*bi.biBitCount)即可完成换算 LineBytes=(DWORD)WIDTHBYTES(bi.biWidth*bi.biBitCount); //ImgSize为实际的图象数据占用的字节数 ImgSize=(DWORD)LineBytes*bi.biHeight; //NumColors为实际用到的颜色数,即调色板数组中的颜色个数 if(bi.biClrUsed!=0) //如果bi.biClrUsed 不为零,即为实际用到的颜色数 NumColors=(DWORD)bi.biClrUsed; else //否则,用到的颜色数为2biBitCount switch(bi.biBitCount){ case 1: NumColors=2; break; case 4: NumColors=16; break; case 8: NumColors=256; break; case 24: NumColors=0; //对于真彩色图,没用到调色板 break; default: //不处理其它的颜色数,认为出错。 MessageBox(hWnd,"Invalid color numbers!","Error Message", MB_OK|MB_ICONEXCLAMATION); _lclose(hf); return FALSE; //关闭文件,返回FALSE } if(bf.bfOffBits!=(DWORD)(NumColors*sizeof(RGBQUAD)+ sizeof(BITMAPFILEHEADER)+ sizeof(BITMAPINFOHEADER))) { //计算出的偏移量与实际偏移量不符,一定是颜色数出错 MessageBox(hWnd,"Invalid color numbers!","Error Message",MB_OK|MB_ICONEXCLAMATION); _lclose(hf); return FALSE; //关闭文件,返回FALSE } //分配内存,大小为INFOHEADER和FILEHEADER结构长度+调色板+实际位图 bf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+ NumColors*sizeof(RGBQUAD)+ImgSize; if ((hImgData=GlobalAlloc(GHND,(DWORD) (sizeof(BITMAPINFOHEADER)+ NumColors*sizeof(RGBQUAD)+ ImgSize)))==NULL) { //分配内存错误 MessageBox(hWnd,"Error alloc memory","Error Message",MB_OK|MB_ICONEXCLAMATION); _lclose(hf); return FALSE; } //指针lpImgData指向该内存区 lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); //文件指针重新定位到BITMAPINFOHEADER开始处 _llseek(hf,sizeof(BITMAPFILEHEADER),SEEK_SET); //将文件内容读入lpImgData _hread(hf,(char*)lpImgData,(long)sizeof(BITMAPINFOHEADER) +(long)NumColors*sizeof(RGBQUAD)+ImgSize); _lclose(hf); //使用了调色板 if(NumColors!=0) { //为逻辑调色板分配局部内存,大小为逻辑调色板结构长度加 //NumColors个PALETTENTRY hPal = LocalAlloc(LHND,sizeof(LOGPALETTE)+ NumColors*sizeof(PALETTEENTRY)); //指针pPal指向该内存区 pPal = (LOGPALETTE*)LocalLock(hPal); //填写逻辑调色板结构的头 pPal->palNumEntries = (WORD)NumColors; pPal->palVersion = 0x300; //lpRGB指向的是调色板开始的位置 lpRGB = (LPRGBQUAD)((LPSTR)lpImgData+ (DWORD)sizeof(BITMAPINFOHEADER)); //填写每一项 for(i=0;i<NumColors;i++){ pPal->palPalEntry[i].peRed = lpRGB->rgbRed; pPal->palPalEntry[i].peGreen = lpRGB->rgbGreen; pPal->palPalEntry[i].peBlue = lpRGB->rgbBlue; pPal->palPalEntry[i].peFlags = (BYTE)0; lpRGB++; } //产生逻辑调色板,hPalette是一个全局变量 hPalette = CreatePalette(pPal); //释放局部内存 LocalUnlock(hPal); LocalFree(hPal); } //获得设备上下文句柄 hDc = GetDC(hWnd); if (hPalette) { //将新的逻辑调色板选入DC,将旧的句柄保存在//hPrevPalette hPrevPalette = SelectPalette(hDc,hPalette,FALSE); RealizePalette(hDc); } //产生位图句柄 hBitmap= CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpImgData, (LONG)CBM_INIT, (LPSTR)lpImgData+sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpImgData,DIB_RGB_COLORS); //将原来的调色板(如果有的话)选入设备上下文句柄 if(hPalette&&hPrevPalette) { SelectPalette(hDc,hPrevPalette,FALSE); RealizePalette(hDc); } ReleaseDC(hWnd,hDc); GlobalUnlock(hImgData);//解锁内存区 return TRUE; }
相关文章推荐
- 用VC6.0编写Win32程序加载文本文件
- 一个服务程序框架,并在vc6.0win32控制台工程中嵌入manifest使用uac
- VC6.0配置汇编环境并编写第一个Hello World程序
- ARM程序工程Makefile 讲解及通用版例子编写
- Eclipse4.7基础 新建工程 编写HelloWorld程序
- vba 开发的dvb程序,现在提示“无法从文件加载工程”?
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- Win7 64位下让VC++6.0编写的Win32程序单进程运行内存突破2G
- 基于对话框的MFC程序加载位图为背景图案
- Win32下Foxbase+数据库浏览程序的编写
- Win32编写窗口程序的步骤
- VC6.0 工程转到VS2008一些问题的描述及解决方法(附有VS2008发布程序介绍)
- 用C#加载C++编写的win32dll
- huffman算法编写的压缩软件程序源代码
- 一个使用Win32SDK编写Windows GUI程序的教程: "theForger's Win32 API Tutorial"
- 用 C 语言编写 Windows 服务程序的五个步骤(附源代码)
- error:2014-03-11周二:在编写win32程序时依旧使用控制台程序。
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- C语言:编写一个程序,它从标准输入(终端)读取C源代码,并验证所有的花括号都正确的成对出现
- 编写一个程序,它从标准输入读取C源代码,并验证所有的花括号都正确的成对出现