[Image] [Image] [Image] [Image] [Image] [Image] [Image] [Return] Using a Metafile [Return] --------------------------------------------------------------------------- Metafiles are essentially "GDI macros". When you create a metafile and perform GDI operations (Rectangle(), MoveToEx(), etc) on it's device context, you actually create a series of GDI operations which may be played back at a later time. Big deal? Well, it can be, depending on what you're doing. For example, if you draw a series of items on a window and want to scale the items according to window size, you can do it one of two ways. The first, of course, is to draw all the items in WM_PAINT. It works, but it's a pain to code and makes programming look like real work (ugh). The second is to draw all the items once into a metafile, then simply play back the metafile in WM_PAINT. Also, If you've ever scaled a bitmap, you've seen how quickly any text it contains becomes unreadable. With metafiles, the font is scaled as a font as opposed to simply dumping or adding raster lines in a bitmap. Thus, the text remains quite readable (depending on the font selected) down to a very small size. The following piece of code is a small program which creates and displays a metafile, scaling it when the window size is changed. #define WIN32_LEAN_AND_MEAN #include "windows.h" // ---------------------------------------------------------------------------- LRESULT WINAPI MainWndProc( HWND, UINT, WPARAM, LPARAM ); // Prototypes BOOL DrawNewPicture( void ); // ---------------------------------------------------------------------------- HINSTANCE hInst; // Global instance handle HDC g_hDC; // DC used for life of the program HMETAFILE hMetaFile; // Metafile handle once drawn // ---------------------------------------------------------------------------- int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmd, int nShow ) { WNDCLASS wc; MSG msg; HWND hWnd; if( FindWindow( "MetaTest", NULL ) ) // If already running { // Give other program focus SetFocus( FindWindow( "MetaTest", NULL ) ); // and exit this one return( FALSE ); } wc.style = CS_OWNDC; // Private DC for life of application wc.hInstance = hInstance; wc.lpfnWndProc = MainWndProc; wc.hIcon = NULL; // Force us to draw our own icon from metafile wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 ); wc.lpszClassName = "MetaTest"; wc.lpszMenuName = "MainMenu"; wc.cbClsExtra = wc.cbWndExtra = 0; if( ! RegisterClass( &wc ) ) // Register class or die trying return( FALSE ); hInst = hInstance; hMetaFile = NULL; // Nothing drawn yet // Now create the main window hWnd = CreateWindow( "MetaTest", "Metafile Test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); if( ! hWnd ) return( FALSE ); ShowWindow( hWnd, nShow ); UpdateWindow( hWnd ); while( GetMessage( &msg, NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } return( FALSE ); } // ---------------------------------------------------------------------------- LRESULT WINAPI MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_CREATE: // When window is started g_hDC = GetDC( hWnd ); SetMapMode( g_hDC, MM_ANISOTROPIC ); // Set scalable map mode SetWindowExtEx( g_hDC, 1000, 1000, NULL ); SetViewportExtEx( g_hDC, 1000, 1000, NULL ); break; case WM_DESTROY: // When window is ending if( hMetaFile ) // If the metafile lingers, kill it { DeleteMetaFile( hMetaFile ); hMetaFile = NULL; } ReleaseDC( hWnd, g_hDC ); // Give up our DC and exit PostQuitMessage( 0 ); break; case WM_SIZE: // When window is resized { // Which includes iconic RECT Rect; // Scale the drawing when the window GetClientRect( hWnd, &Rect ); // size is changed SetViewportExtEx( g_hDC, Rect.right, Rect.bottom, NULL ); InvalidateRect( hWnd, NULL, TRUE ); // and force a redraw break; } case WM_PAINT: // When the window needs painted { PAINTSTRUCT Ps; if( hMetaFile ) // If there's something to draw { BeginPaint( hWnd, &Ps ); PlayMetaFile( g_hDC, hMetaFile ); // play back metafile EndPaint( hWnd, &Ps ); } else // If no metafile defined, let Windows do the work return( DefWindowProc( hWnd, msg, wParam, lParam ) ); break; } case WM_COMMAND: // User stuff if( wParam == 100 ) { if( DrawNewPicture() ) // Draw! selected InvalidateRect( hWnd, NULL, TRUE ); // Force redraw if OK break; } if( wParam == 101 ) { if( hMetaFile ) // Exit selected, kill metafile is any { DeleteMetaFile( hMetaFile ); hMetaFile = NULL; } PostQuitMessage( 0 ); break; } break; default: return( DefWindowProc( hWnd, msg, wParam, lParam ) ); } return( FALSE ); } // ---------------------------------------------------------------------------- BOOL DrawNewPicture( void ) // Note this program uses a memory based { // metafile. Instead, a file based meta HDC hMetaDC; // is created by passing a valid filename to HBRUSH hBrush; // CreateMetaFile(). GetTempFileName() could HFONT hFont; // be used to generate a unique filename which only // needs to be renamed if "saved" if( hMetaFile ) DeleteMetaFile( hMetaFile ); hMetaDC = CreateMetaFile( NULL ); // Create a new memory based metafile if( ! hMetaDC ) return( FALSE ); hBrush = CreateSolidBrush( RGB( 128, 0, 0 ) ); // Draw something on it SelectObject( hMetaDC, hBrush ); Rectangle( hMetaDC, 0, 0, 1000, 1000 ); // Fill with a rectangle hBrush = CreateSolidBrush( RGB( 255, 255, 0 ) ); DeleteObject( SelectObject( hMetaDC, hBrush ) ); Ellipse( hMetaDC, 250, 250, 750, 750 ); // Draw yellow circle hBrush = CreateSolidBrush( RGB( 0, 255, 0 ) ); DeleteObject( SelectObject( hMetaDC, hBrush ) ); Rectangle( hMetaDC, 400, 400, 600, 600 ); // Draw green rectangle SelectObject( hMetaDC, GetStockObject( BLACK_PEN ) ); MoveToEx( hMetaDC, 0, 0, NULL ); LineTo( hMetaDC, 1000, 1000 ); // Draw "X" in window MoveToEx( hMetaDC, 0, 1000, NULL ); LineTo( hMetaDC, 1000, 0 ); SetBkColor( hMetaDC, RGB( 255, 0, 0 ) ); SetTextColor( hMetaDC, RGB( 255, 255, 255 ) ); hFont = CreateFont( -40, // Specify height and width so -16, // the font scales somewhat normally 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, DEFAULT_PITCH | FF_DONTCARE, "Arial" ); // Select a scalable font if( hFont ) SelectObject( hMetaDC, hFont ); TextOut( hMetaDC, 10, 100, "Text Scales, also.", 18 ); if( hFont ) DeleteObject( SelectObject( hMetaDC, GetStockObject( SYSTEM_FONT ) ) ); DeleteObject( SelectObject( hMetaDC, GetStockObject( NULL_BRUSH ) ) ); // Closing the metafile returns the metahandle hMetaFile = CloseMetaFile( hMetaDC ); return( TRUE ); }