18.2.7 增强型图元文件的查看和打印程序
(1)传递EMF到剪贴板,剪贴板类型应为:CF_ENHMETAFILE
(2)CopyEnhMetaFile用于复制图元文件
(3)剪贴板中的图元文件会自动在老式与增强型图元文件间转换。
(4)自定义函数CreatePaletteFromMetaFile用于从图元文件中创建逻辑调色板。
【EmfView程序】
/*------------------------------------------------------------ EMFVIEW.C -- View Enhanced Metafiles (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName[] = TEXT("EmfView"); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd ; MSG msg ; WNDCLASS wndclass ; HACCEL hAccel; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = szAppName ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, // window class name TEXT ("Enhanced Metafile Viewer"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; hAccel = LoadAccelerators(hInstance, szAppName); while (GetMessage (&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd,hAccel,&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam ; } HPALETTE CreatePaletteFromMetaFile(HENHMETAFILE hemf) { HPALETTE hPalette; LOGPALETTE* plp; int iNum; if (!hemf) return NULL; //获取图元文件中的调色板数目 if (0 == (iNum = GetEnhMetaFilePaletteEntries(hemf, 0, NULL))) return NULL; plp = malloc(sizeof(LOGPALETTE)+(iNum - 1)*sizeof(PALETTEENTRY)); plp->palVersion = 0x0300; plp->palNumEntries = iNum; GetEnhMetaFilePaletteEntries(hemf, iNum, plp->palPalEntry); //获取图元文件调色板中的各个颜色条目 hPalette = CreatePalette(plp); free(plp); return hPalette; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static OPENFILENAME ofn; static TCHAR szFilter[] = TEXT("Enhanced Metafiles(*.EMF) *.emf ") TEXT("All Files (*.*) *.* "); static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH]; static DOCINFO di = { sizeof(DOCINFO), TEXT("EmfView:Printing") }; static PRINTDLG printdlg = { sizeof(PRINTDLG) }; BOOL bSuccess; HDC hdcPrn; HDC hdc ; PAINTSTRUCT ps ; RECT rect ; static HENHMETAFILE hemf; HENHMETAFILE hemfCopy; HMENU hMenu; int iEnable; HPALETTE hPalette; PTSTR pBuffer; int i,iLength; ENHMETAHEADER header; switch (message) { case WM_CREATE: //初始化OPENFILENAME结构体 memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = szFilter; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = szTitleName; ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrDefExt = TEXT("emf"); return 0 ; case WM_INITMENUPOPUP: hMenu = GetMenu(hwnd); iEnable = hemf ? MF_ENABLED : MF_GRAYED; EnableMenuItem(hMenu, IDM_FILE_SAVE_AS, iEnable); EnableMenuItem(hMenu, IDM_FILE_PRINT, iEnable); EnableMenuItem(hMenu, IDM_FILE_PROPERTIES, iEnable); EnableMenuItem(hMenu, IDM_EDIT_CUT, iEnable); EnableMenuItem(hMenu, IDM_EDIT_COPY, iEnable); EnableMenuItem(hMenu, IDM_EDIT_DELETE, iEnable); EnableMenuItem(hMenu, IDM_EDIT_PASTE, IsClipboardFormatAvailable(CF_ENHMETAFILE) ? MF_ENABLED : MF_GRAYED); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_OPEN: //显示打开文件对话框 ofn.Flags = 0; if (!GetOpenFileName(&ofn)) return 0; //如果emf文件己经在内存中,则删掉。 if (hemf) { DeleteEnhMetaFile(hemf); hemf = NULL; } //加载emf文件 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); hemf = GetEnhMetaFile(szFileName); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); //发送重绘客户区消息 InvalidateRect(hwnd, NULL, TRUE); if (hemf == NULL) { MessageBox(hwnd, TEXT("Cannot load metafile"), szAppName, MB_ICONEXCLAMATION | MB_OK); } return 0; case IDM_FILE_PRINT: if (!hemf) return 0; //显示打印对话框 printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION; if (!PrintDlg(&printdlg)) return 0; if (NULL ==(hdcPrn=printdlg.hDC)) { MessageBox(hwnd, TEXT("Cannot obtain printer DC"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; } //获得页面的可打印区域 rect.left = 0; rect.right = GetDeviceCaps(hdcPrn, HORZRES); rect.top = 0; rect.bottom = GetDeviceCaps(hdcPrn, VERTRES); bSuccess = FALSE; //在打印机设备中回放emf文件,即将emf绘制在打印机上 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); if (StartDoc(hdcPrn,&di)>0 && (StartPage(hdcPrn)>0)) { PlayEnhMetaFile(hdcPrn, hemf, &rect); if (EndPage(hdcPrn)>0) { bSuccess = TRUE; EndDoc(hdcPrn); } } ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); DeleteDC(hdcPrn); if (!bSuccess) { MessageBox(hwnd, TEXT("Could not print metafile"), szAppName, MB_ICONEXCLAMATION | MB_OK); } return 0; case IDM_FILE_PROPERTIES: if (!hemf) return 0; iLength = GetEnhMetaFileDescription(hemf, 0, NULL); //字符串的字符个数 pBuffer = malloc((iLength + 256)*sizeof(TCHAR)); GetEnhMetaFileHeader(hemf, sizeof(ENHMETAHEADER), &header); //格式化头记录信息 i = wsprintf(pBuffer, TEXT("Bounds =(%i,%i,) to (%i,%i) pixels "), header.rclBounds.left,header.rclBounds.top, header.rclBounds.right,header.rclBounds.bottom); i += wsprintf(pBuffer+i, TEXT("Frame =(%i,%i,) to (%i,%i) mms "), header.rclFrame.left, header.rclFrame.top, header.rclFrame.right, header.rclFrame.bottom); i += wsprintf(pBuffer + i, TEXT("Resolution =(%i,%i,) pixels ") TEXT(" =(%i,%i,) mms "), header.szlDevice.cx,header.szlDevice.cy, header.szlMillimeters.cx,header.szlMillimeters.cy); i += wsprintf(pBuffer + i, TEXT("Size = %i, Recoreds = %i, ") TEXT("Handles = %i, Palette Entries = %i "), header.nBytes,header.nRecords, header.nHandles,header.nPalEntries); if (iLength) { i += wsprintf(pBuffer + i, TEXT("Description = ")); GetEnhMetaFileDescription(hemf, iLength, pBuffer + i); //注意缓冲区大小为iLength // pBuffer内容形如"......EMF3 EMF3 Demo #3 "。MessageBox遇 时会结束,为了 //防止出现这种情况,可将把字符串中间出现的 替换成空格。此字符串中间只有一个, //又因lstrlen()函数会计算字符串长度,也是遇 结束并且长度不含 ,可用 //如下代码替换。 pBuffer[lstrlen(pBuffer)] = TEXT(' '); } MessageBox(hwnd, pBuffer, TEXT("Metafile Properties"), MB_OK); free(pBuffer); return 0; case IDM_FILE_SAVE_AS: if (!hemf) return 0; //打开“保存”文件对话框 ofn.Flags = OFN_OVERWRITEPROMPT; if (!GetSaveFileName(&ofn)) return 0; //保存emf到磁盘 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); //CopyEnhMetaFile将hemf拷到szFileName指定的文件中,并返回副本的句柄. hemfCopy = CopyEnhMetaFile(hemf, szFileName); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); if (hemfCopy) { DeleteEnhMetaFile(hemf); hemf = hemfCopy; //将拷贝的副本设为当前的图元文件 } else MessageBox(hwnd, TEXT("Cannot Save metafile"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; case IDM_EDIT_COPY: case IDM_EDIT_CUT: if (!hemf) return 0; hemfCopy = CopyEnhMetaFile(hemf, NULL); OpenClipboard(hwnd); EmptyClipboard(); SetClipboardData(CF_ENHMETAFILE, hemfCopy); CloseClipboard(); if (LOWORD(wParam) == IDM_EDIT_COPY) return 0; //如果是剪切,则继续执行下去。 case IDM_EDIT_DELETE: if (hemf) { DeleteEnhMetaFile(hemf); hemf = NULL; InvalidateRect(hwnd, NULL, TRUE); } return 0; case IDM_EDIT_PASTE: OpenClipboard(hwnd); hemfCopy = GetClipboardData(CF_ENHMETAFILE); CloseClipboard(); if (hemfCopy && hemf) { DeleteEnhMetaFile(hemf); hemf = NULL; } hemf = CopyEnhMetaFile(hemfCopy, NULL); DeleteEnhMetaFile(hemfCopy); InvalidateRect(hwnd, NULL, TRUE); return 0; case IDM_APP_EXIT: SendMessage(hwnd, WM_CLOSE, 0, 0); return 0; case IDM_APP_ABOUT: MessageBox(hwnd, TEXT("Enhanced Metafile Viewer ") TEXT("(c)Charles Petzold,1998"), szAppName,MB_OK); return 0; } case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; if (hemf) { if (hPalette = CreatePaletteFromMetaFile(hemf)) { SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); } //回放图元文件 PlayEnhMetaFile(hdc, hemf, &rect); if (hPalette) { DeleteObject(hPalette); } } EndPaint (hwnd, &ps) ; return 0 ; case WM_QUERYNEWPALETTE: //窗口被激活时,收到此消息 if (!hemf || !(hPalette = CreatePaletteFromMetaFile(hemf))) return FALSE; hdc = GetDC(hwnd); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); InvalidateRect(hwnd, NULL, FALSE); DeleteObject(hPalette); ReleaseDC(hwnd, hdc); return TRUE; case WM_PALETTECHANGED: if ((HWND)wParam == hwnd) break; if (!hemf || !(hPalette = CreatePaletteFromMetaFile(hemf))) break; hdc = GetDC(hwnd); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); UpdateColors(hdc); DeleteObject(hPalette); ReleaseDC(hwnd, hdc); break; case WM_DESTROY: if (hemf) DeleteEnhMetaFile(hemf); PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 EmfView.rc 使用 // #define IDM_FILE_OPEN 40001 #define IDM_FILE_SAVE_AS 40002 #define IDM_FILE_PRINT 40003 #define IDM_FILE_PROPERTIES 40004 #define IDM_APP_EXIT 40005 #define IDM_EDIT_CUT 40006 #define IDM_EDIT_COPY 40007 #define IDM_EDIT_PASTE 40008 #define IDM_EDIT_DELETE 40009 #define IDM_APP_ABOUT 40010 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40019 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//EmfView.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h " END 2 TEXTINCLUDE BEGIN "#include ""winres.h"" " "