YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
XD++ Library
DocVizor
TFC Library
Free Products
Technical Support
UCanCode.net


Get Ready to Unleash the Power of UCanCode .NET


UCanCode Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!

"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"


ActiveX Control Tutorial, COleControl

 
 Kapil Chaturvedi
January 21, 2001 

Introduction

ActiveX Programming

This article is for those enthusiastic VC++ developers who want to build their own ActiveX controls but don’t know where to start with. This article will take you to build your first ActiveX control. This article will show you the step by step method to build a control which draws different waveforms (Sin/Cos).I assume that you are familiar with VC++ and know some basics of ActiveX control.

Creating an ActiveX Control

Simply follow these steps in order to create an ActiveX control.

  1. Using the AppWizard to create an ActiveX Control project

    1. Select New from File menu

    2. Click the Projects tab and select the type of project as MFC ActiveX Control Wizard from the list.

    3. Name of new project Plot and then click the OK button.

    4. Take all the defaults values of the next dialog (titled MFC ActiveX Control Wizard - Step 1 of 2) and click the Next button

    5. From the next dialog (titled MFC ActiveX Control Wizard - Step 2 of 2), locate the combo box with the prompt Which window class, if any, should this control subclass?. Drop down the list and select the entry STATIC from that list. We're using a static control in this example since we'll just be displaying data (and not accepting input).

    6. Click on Advanced button and check the Flicker free activation checkbox.

    7. Now click the Finish button. At this point, the AppWizard will generate the following three classes on your behalf:

      • CPlotApp - The ActiveX "appliction" class is derived from COleControlModule. The COleControlModule class is the base class from which you derive an OLE control module object. This class provides member functions for your control module's initialization (InitInstance) and cleanup code (ExitInstance).

      • CPlotCtrl - The second class is derived from COleControl and will provide most of the functionality to your control. This is the class where you will write the majority of the your code.

      • CPlotPropPage - The third class is CPlotPropPage, (derived from COlePropertyPage). This class is used to manage the property page dialog of your control. In addition to this class, a dialog resource is also created that will serve as the property page for the control.

  2. Adding "Stock" properties
    The term stock properties means that its one of a set of common properties that MFC code stores and initializes for you. The MFC code also performs appropriate action when the value of a stock property is changed. The ClassWizard provides code for changing nine (9) such properties. Since these properties are built-in, they are obviously the easiest to deal with in terms of the work required by the developer. As you'll see shortly, you literally don't add a single line of code to add stock property to your control!

    The ClassWizard provides code for the following stock properties:

    • Appearance

    • BackColor

    • ForeColor

    • BorderStyle

    • Font

    • Caption

    • Enable

    • Text

    • hWnd

    From these, we will work with the Appearance, BackColor, ForeColor and BorderStyle properties.

    We'll start by adding the BackColor stock property

     

    1. From the ClassWizard, click the Automation tab.

    2. Ensure that the CPlotCtrl class is selected in the Class name combobox. Now, Click the Add Property button to display the Add Property dialog.

    3. Once the Add Property dialog does appear, select the BackColor property from the External Name combo box. (It is called the "external name" because this is how users of the control will refer to it.)

    4. Verify that the Stock radio button is selected in the Implementation groupbox.

    5. Click the OK button to finish the generation of the stock property. At this point, the ClassWizard will store the value of the BackColor property and initialize it to background color of the container window. The ClassWizard will also add the following line to your control's ODL file:

      [id(DISPID_BACKCOLOR), bindable, requestedit] OLE_COLOR BackColor;
      

      Finally, ClassWizard will also add the code to invalidate the control whenever the value of the BackColor property changes, thereby forcing the OnDraw function to redraw the control. The only thing you have to do is to use the color contained in the property to paint the background color of control.

    6. At this point, add the following two (2) lines of code to the end of the CPlotCtrl::OnDraw member function

      CBrush bkBrush(TranslateColor(GetBackColor()));
      pdc->FillRect(rcBounds,&bkBrush);
      
    7. Now, let's add a Color property page to the program. This page will allow users of the control to change the BackColor our newly added property property at design-time. To do this, simply open the PlotCtrl.cpp file and locate the // Property pages comment.

      Once you've done that, you should see the following:

      BEGIN_PROPPAGEIDS(CPlotCtrl, 1)
       PROPPAGEID(CPlotPropPage::guid)
      END_PROPPAGEIDS(CPlotCtrl)
      

      The first line tells the compiler how many pages exist. Notice that it's set to 1. Change this value to 2 as we're going to add a new page.

      Now insert the following line just before the END_PROPPAGEIDS line (The CLSID_CColorPropPage is defined automatically since this is a property page CLSID for a stock property).

      PROPPAGEID(CLSID_CColorPropPage)
      

      Once you've finished, your new property page id map should look like the following:

      BEGIN_PROPPAGEIDS(CPlotCtrl, 2)
       PROPPAGEID(CPlotPropPage::guid)
       PROPPAGEID(CLSID_CColorPropPage)
      END_PROPPAGEIDS(CPlotCtrl)
      

      Once you make the above changes,the stock property page is automatically linked to the BackColor property.

    8. Now that you've seen how to add the BackColor stock property to an ActiveX control, follow these same steps in order to add the Appearance, ForeColor and BorderStyle properties. Note that you do not need to add a property page for the other properties.

    9. After adding these stock properties, build your control and test it using ActiveX Test Container (which is usually found under the Tools menu. As you can see in the figure below, the ClassWizard has added the appropriate controls for changing the stock properties.

  3. Adding Custom Properties
    Custom properties are properties you devise yourself for your control. For the plot control I have added only four custom properties "Grid On/Off" and "X-Log". The grid properties will control the visibility of the control grid. The "x-log" property will be used to plot the horizontal axis in the logarithmic scale. Let's start with the grid properties.

    1. From the ClassWizard, click the Automation tab.

    2. Ensure that the CPlotCtrl class is selected in the Class name combobox. Now, Click the Add Property button to display the Add Property dialog.

    3. Once the Add Property dialog is displayed, enter ShowGrid into the External Name combo box.

    4. Then select BOOL as the properties type.

    5. Verify that the Member Variable radio button selected in the Implementation group box.

    6. Click the OK button to have the ClassWizard create a boolean custom property named ShowGrid. Also note that the internal member variable name (the name used in the control's code) is m_showGrid. Now, whenever the container changes the value of this property, the MFC code will reflect that value in the m_showGrid member variable and will call the CPlotCtrl::OnShowGridChanged notification function.

    7. Because ShowGrid is a custom property, we have to write our own initialization and implementation code. Add the following code (marked in bold) in order to initialize the m_showGrid member variable.

      void CPlotCtrl::DoPropExchange(CPropExchange* pPX)
      {
       ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
       COleControl::DoPropExchange(pPX);
      
       PX_Bool(pPX,_T("ShowGrid"),m_showGrid,FALSE);
      }
      

      Locate the CPlotCtrl::OnShowGridChanged member function that the ClassWizard added to your code when you created the ShowGrid property (it should be at the end of the PlotCtl.cpp file. Insert the following line (marked in bold) to that function. (This call simply invalidate the control when the ShowGrid property value is changed)

      void CPlotCtrl::OnShowGridChanged()
      {
       InvalidateControl();
       SetModifiedFlag();
      }
      
    8. Since ShowGrid is a custom property we have to do little more work to have it included on the property page. To do this, open the Resource View tab and open the Property page dialog (IDD_PROPPAGE_PLOT).

    9. Using the dialog editor add a check box with the ID IDC_CHECK1 and text value of "Show Grid".

    10. Run the ClassWizard, select the Member Variables tab

    11. Add a member variable for the control id IDC_CHECK1 called m_bShowGrid of type BOOL. Make sure that you set the Optional property name to ShowGrid. When you're finished, the dialog should look like the figure below.

    12. Now, add the custom property "X-Log" where the following values are shown in the following figure.

    13. Add the following line of code to the CPlotCtrl::DoPropExchange member function:

      PX_Bool(pPX,_T("ShowGrid"),m_xLog,FALSE);
      
    14. Just as you did with the ShowGrid property, add a checkbox to the control's property page for the X-Log property and then add a member variable for it as well.

    15. Insert the following code (marked in bold) in the CPlotCtrl::OnXLogChanged member function

      void CPlotCtrl::OnXLogChanged()
      {
        InvalidateControl();
      	SetModifiedFlag();
      }
      
    16. To implement these properties, add the following members to the control:

      private:
       CRect wndRect,m_DrawRect;
       CDC* m_pDC;
      
       //Function to Intialize DC and mapping mode
       void PrepareForPlotting(CRect rect);
       void DrawGrid();
      
    17. Modify the CPlotCtrl::OnDraw member function as follows. (Note: you will need to include the math.h file due to the use of the sin function)

      //Function to plot Grid
      void CPlotCtrl::OnDraw(CDC* pdc,
                                 const CRect& rcBounds,
                                 const CRect& rcInvalid)
      {
       DoSuperclassPaint(pdc, rcBounds);
      
       m_pDC = pdc;
       m_DrawRect = rcBounds;
       wndRect = rcBounds;
      
       PrepareForPlotting(&rcBounds);
      
       CBrush hbrBackground(TranslateColor(GetBackColor()));
       pdc->FillRect (m_DrawRect,&hbrBackground);
      
       if(m_showGrid)
        DrawGrid();
      
       float y;
       m_pDC->SelectObject(CPen(PS_SOLID,1,GetForeColor()));
       m_pDC->MoveTo(m_DrawRect.right/2,
       m_DrawRect.bottom/2);
       for (int i=0;i<2000;i=i++)
       {
        y = 512*sin(2*3.1415926535*i/1000)+512;
        m_pDC->MoveTo(i , y);
        m_pDC->LineTo(i+1 ,
        512*sin(2*3.1415926535*(i+1)/1000)+512);
       }
      }
      
    18. Add the following code for the DrawGrid function that you declared.

      
      void CPlotCtrl::DrawGrid()
      {
       CPen Pen (PS_SOLID|PS_INSIDEFRAME,1,TranslateColor(GetForeColor()));
       CPen* oldPen = m_pDC->SelectObject (&Pen);
      
       switch(m_xLog)
       {
        case FALSE:
         int i;
      
         for (i = m_DrawRect.left;
              i <= m_DrawRect.right ;
              i = i+(( m_DrawRect.right - m_DrawRect.left )/10))
         {
          m_pDC->MoveTo (i, m_DrawRect.top );
          m_pDC->LineTo (i, m_DrawRect.bottom );
         }
      
         for (i = m_DrawRect.top;
              i <= m_DrawRect.bottom;
              i = i+ (( m_DrawRect.bottom - m_DrawRect.top )/8))
         {
          m_pDC->MoveTo (m_DrawRect.left,i );
          m_pDC->LineTo (m_DrawRect.right,i);
         }
        break;
      
        case TRUE:
         int x,X;
      
         for(int j=1;j<= 10;j++)
         {
          x= (int)(log10(j)*285.7143);
          m_pDC->MoveTo (x,m_DrawRect.top);
          m_pDC->LineTo (x,m_DrawRect.bottom );
         }
      
         X= x;
      
         m_pDC->SelectObject(&Pen);
         m_pDC->MoveTo (x,m_DrawRect.top);
         m_pDC->LineTo (x,m_DrawRect.bottom );
         m_pDC->SelectObject (&Pen);
         m_pDC->TextOut (x,m_DrawRect.bottom-5,"10.0K");
      
         for( j=1;j<= 10;j++)
         {
          x= X+(int)(log10(j)*285.7143);
          m_pDC->MoveTo (x,m_DrawRect.top);
          m_pDC->LineTo (x,m_DrawRect.bottom );
         }
      
         X= x;
      
         m_pDC->SelectObject(&Pen);
         m_pDC->MoveTo (x,m_DrawRect.top);
         m_pDC->LineTo (x,m_DrawRect.bottom );
         m_pDC->SelectObject (&Pen);
         m_pDC->TextOut (x,m_DrawRect.bottom-5,"100.0K");
      
         for( j=1;j<= 10;j++)
         {
          x= X+(int)(log10(j)*285.7143);
          m_pDC->MoveTo (x,m_DrawRect.top);
          m_pDC->LineTo (x,m_DrawRect.bottom );
         }
      
         X= x;
      
         m_pDC->SelectObject(&Pen);
         m_pDC->MoveTo (x,m_DrawRect.top);
         m_pDC->LineTo (x,m_DrawRect.bottom );
         m_pDC->SelectObject (&Pen);
         m_pDC->TextOut (x,m_DrawRect.bottom-5,"1.0M");
      
         for( j=1;j<= 10;j++)
         {
          x= X+(int)(log10(j)*285.7143);
          m_pDC->MoveTo (x,m_DrawRect.top);
          m_pDC->LineTo (x,m_DrawRect.bottom );
         }
      
         X= x;
      
         m_pDC->SelectObject(&Pen);
         m_pDC->MoveTo (x,m_DrawRect.top);
         m_pDC->LineTo (x,m_DrawRect.bottom );
         m_pDC->SelectObject (&Pen);
         m_pDC->TextOut (x,m_DrawRect.bottom-5,"10.0M");
      
         for( j=1;j<= 10;j++)
         {
          x= X+(int)(log10(j)*285.7143);
          m_pDC->MoveTo (x,m_DrawRect.top);
          m_pDC->LineTo (x,m_DrawRect.bottom );
         }
      
         X= x;
      
         m_pDC->SelectObject(&Pen);
         m_pDC->MoveTo (x,m_DrawRect.top);
         m_pDC->LineTo (x,m_DrawRect.bottom );
         m_pDC->SelectObject (&Pen);
         m_pDC->TextOut (x,m_DrawRect.bottom-5,"10.0M");
      
         for( j=1;j<= 10;j++)
         {
          x= X+(int)(log10(j)*285.7143);
          m_pDC->MoveTo (x,m_DrawRect.top);
          m_pDC->LineTo (x,m_DrawRect.bottom );
         }
      
         X= x;
      
         m_pDC->SelectObject(&Pen);
         m_pDC->MoveTo (x,m_DrawRect.top);
         m_pDC->LineTo (x,m_DrawRect.bottom );
         m_pDC->SelectObject (&Pen);
         m_pDC->TextOut (x,m_DrawRect.bottom-5,"10.0M");
      
         for( j=1;j<= 10;j++)
         {
          x= X+(int)(log10(j)*285.7143);
          m_pDC->MoveTo (x,m_DrawRect.top);
          m_pDC->LineTo (x,m_DrawRect.bottom );
         }
      
        break;
       }
      }
      
    19. Add the following code for the PrepareForPlotting function that you declared.

      void CPlotCtrl::PrepareForPlotting(CRect rect)
      {
       m_pDC->SetMapMode(MM_HIMETRIC);
       m_pDC->SetMapMode(MM_ANISOTROPIC);
       m_pDC->SetWindowExt (2000,1024);
       m_pDC->SetViewportExt (rect.right , rect.bottom );
       m_pDC->DPtoLP(&m_DrawRect);
      
       return;
      }
      

At this point, you have completed your control and should be able to build and test it using the ActiveX Test Container The following figure shows an example of the control being tested.

About Author

Kapil is a software engineer at Scientific Mes-Technik. He has been working with Visual C++ for the past three years, developing ActiveX controls. Presently he is looking for a job offer from a U.S. company.

Downloads

Download demo project - 16 Kb

 

 

Copyright ?1998-2007 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net