![]() |
Multimedia »
GDI+ »
General
Intermediate
GDI+ in ActiveX Controls Using MFCBy Ryan JohnstonAn article on using GDI+ in an ActiveX control |
VC6, VC7, VB 6Win2K, WinXP, MFC, GDI+, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

#include "gdiplus.h" to include the headers. I usually add it to stdafx.h so I can use GDI+ anywhere in my program.Gdiplus::GdiplusStartup before you do any GDI+ calls.Gdiplus::GdiplusShutdown after you are done with GDI+. COleControl derived class's constructor, and shut down in its destructor, then everything seems to work.Gdiplus::GdiplusStartup is issued per process,
because I have read several posts that seem to indicate that people have run into problems when Gdiplus::GdiplusStartup
is called too many times. In order to properly start and stop GDI+ in an ActiveX control, I initialized GDI+ in the constructor of
my COleControl derived class, and shut it down in the destructor using methods provided by the
InitGDIPlus class.class InitGDIPlus { private: HANDLE m_hMap; bool m_bInited, m_bInitCtorDtor; ULONG_PTR m_gdiplusToken; Gdiplus::GdiplusStartupInput m_gdiplusStartupInput; long m_initcount; public: // Constructor offers the ability to initialize on construction, or delay until needed. InitGDIPlus(bool bInitCtorDtor = false) : m_bInitCtorDtor(bInitCtorDtor), m_bInited(false), m_hMap(NULL), m_gdiplusToken(NULL), m_gdiplusStartupInput(NULL), m_initcount(0) { if (m_bInitCtorDtor) { Initialize(); } } // If GDI+ has not been explicitly Deinitialized, do it in the destructor virtual ~InitGDIPlus() { if (m_bInitCtorDtor) { Deinitialize(); } } // This function creates a file mapping based on the current process id. // If the mapping already exists, it knows that another instance of this class // elsewhere in the process has already taken care of starting GDI+. void Initialize() { if (!m_bInited) { char buffer[1024]; sprintf(buffer, "GDIPlusInitID=%x", GetCurrentProcessId()); m_hMap = CreateFileMapping((HANDLE) INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, sizeof(long), buffer); if (m_hMap != NULL) { // We might have a winner if (GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(m_hMap); } else { // Yes, we have a winner m_bInited = true; Gdiplus::GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL); TRACE("Inited GDIPlus\n"); } } } m_initcount++; } // No tricks to this function. If this was the class that // originally started GDI+, and its initialization count has // reached zero, it shuts down GDI+. void Deinitialize() { m_initcount--; if (m_bInited && m_initcount == 0) { TRACE("GDIPlus shutdown\n"); Gdiplus::GdiplusShutdown(m_gdiplusToken); CloseHandle(m_hMap); m_bInited = false; } } };
///////////////////////////////////////////////////////////////////////////// // CGDIPlusControlCtrl::CGDIPlusControlCtrl - Constructor CGDIPlusControlCtrl::CGDIPlusControlCtrl() : m_isClicked(false), m_center(50, 50) { InitializeIIDs(&IID_DGDIPlusControl, &IID_DGDIPlusControlEvents); GDI_Plus_Controler.Initialize(); //GDI_Plus_Controler is a static global } ///////////////////////////////////////////////////////////////////////////// // CGDIPlusControlCtrl::~CGDIPlusControlCtrl - Destructor CGDIPlusControlCtrl::~CGDIPlusControlCtrl() { GDI_Plus_Controler.Deinitialize(); //GDI_Plus_Controler is a static global }One thing to note is that windowless activation is dependent on the ActiveX container, and some containers do not support it. I know it works in VB6, but as far as I can tell, the default container support offered by MFC does not support windowless activation.
OnDraw function to show GDI+ in action. Due to the fact that this OnDraw function draws on a transparent background, this could cause problems if this control does not use windowless activation.
///////////////////////////////////////////////////////////////////////////// // CGDIPlusControlCtrl::OnDraw - Drawing function void CGDIPlusControlCtrl::OnDraw( CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) { using namespace Gdiplus; Graphics graphics(pdc->m_hDC); // Bitmap sized to control size for double buffering Bitmap bmp(rcBounds.Width(), rcBounds.Height()); // Graphics object using the memory bitmap Graphics* pMemoryGraphics = Graphics::FromImage(&bmp); LinearGradientBrush blueGradient(Point(1,1), Point(rcBounds.Width()-2, rcBounds.Height()-2), Color(0, 0, 0, 255), Color(192, 0, 0, 255)); // Create path for the ellipse GraphicsPath gp; gp.StartFigure(); gp.AddEllipse(2,2, rcBounds.Width() -4, rcBounds.Height() - 4); // Set up a radial gradient brush PathGradientBrush whiteGradientHighlight(&gp); whiteGradientHighlight.SetCenterColor(Color(255, 255, 255, 255)); //m_center is manipulated by the mouse handlers whiteGradientHighlight.SetCenterPoint(Point(m_center.x, m_center.y)); whiteGradientHighlight.SetFocusScales(0.1f, 0.1f); Color surroundColors[] = {Color(0, 255, 255, 255)}; int surroundColorsCount = 1; whiteGradientHighlight.SetSurroundColors(surroundColors, &surroundColorsCount); // Done Setting up radial gradient brush if(m_antiAliased) { pMemoryGraphics->SetSmoothingMode(SmoothingModeAntiAlias); } pMemoryGraphics->FillPath(&blueGradient, &gp); pMemoryGraphics->FillPath(&whiteGradientHighlight, &gp); if(m_border) { Pen pen(Color(255,0,0,0), 2); pMemoryGraphics->DrawPath(&pen, &gp); } // Using rcBounds.left and rcBounds.top ensure proper // positioning with windowless activation. graphics.DrawImage(&bmp, rcBounds.left, rcBounds.top); }Included with my project files, I have enclosed a VB6 project that I used to test my control. My control uses a few translucent gradient fills, so it is easy to see how the windowless control blends with the container's background. In VB6 it is easy to change the background, so feel free to play around with it to see how the control incorporates the new color or background image. Here is a screen shot of my container with a background image:

General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 1 Jul 2002 Editor: Chris Maunder |
Copyright 2002 by Ryan Johnston Everything else Copyright © CodeProject, 1999-2009 Web09 | Advertise on the Code Project |