Skip to main content Skip to footer

How do I use VC++ #Import statements with Chart ActiveX?

Wrapper classes can be avoided if you use an #Import statement. In VS.NET, the wrapper classes that are generated for ActiveX controls in vC++ are not very good. The wrappers do not contain all properties, so it is recommended that for VS.NET you either use wrappers generated in vC++ 6 or use the #Import statement. The #Import statement can also be used in vC++ 6 to avoid wrappers. The instructions below will work in both vC++ 6 and all versions of vC++ .NET.

Step 1:

Create a new MFC project in vC++ 6 or .NET.

Step 2:

Create an instance of the chart control by either Right-Clicking on the control and selecting "Insert Active X control" (select desired Chart version from the list), or in code. It is not necessary to create the member variable at design time. The chart variable will be added through code in a later step.

Step 3:

Open StdAfx.h. We will need to add our #Import statements here. Before importing the Chart, we need to use an #Import statement for stdole2.tlb. We do this to get around a conflict between ActiveX controls and other interfaces. This is a Microsoft bug, and has nothing to do with ComponentOne Chart for ActiveX. For more information on the bug, please visit the following link: http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q224610 The following #Import statements should be added immediately before #endif in StdAfx.h if you are using the 2D version of the Chart component:

#import "stdole2.tlb" rename_namespace("OChart2D") \  
exclude("GUID", "DISPPARAMS", "EXCEPINFO", \  
"OLE\_XPOS\_PIXELS", "OLE\_YPOS\_PIXELS", "OLE\_XSIZE\_PIXELS", \  
"OLE\_YSIZE\_PIXELS", "OLE\_XPOS\_HIMETRIC", \  
"OLE\_YPOS\_HIMETRIC", "OLE\_XSIZE\_HIMETRIC", "OLE\_YSIZE\_HIMETRIC", \  
"OLE\_XPOS\_CONTAINER", "OLE\_YPOS\_CONTAINER", "OLE\_XSIZE\_CONTAINER", \  
"OLE\_YSIZE\_CONTAINER", "OLE\_HANDLE", "OLE\_OPTEXCLUSIVE", \  
"OLE\_CANCELBOOL", "OLE\_ENABLEDEFAULTBOOL", "FONTSIZE", "OLE_COLOR")  
#import "olch2x8.ocx" rename_namespace("OChart2D")  
using namespace OChart2D;

If you are using the 3D version of the Chart, the #import statements should look like this:

#import "stdole2.tlb" rename_namespace("OChart3D") \  
exclude("GUID", "DISPPARAMS", "EXCEPINFO", \  
"OLE\_XPOS\_PIXELS", "OLE\_YPOS\_PIXELS", "OLE\_XSIZE\_PIXELS", \  
"OLE\_YSIZE\_PIXELS", "OLE\_XPOS\_HIMETRIC", \  
"OLE\_YPOS\_HIMETRIC", "OLE\_XSIZE\_HIMETRIC", "OLE\_YSIZE\_HIMETRIC", \  
"OLE\_XPOS\_CONTAINER", "OLE\_YPOS\_CONTAINER", "OLE\_XSIZE\_CONTAINER", \  
"OLE\_YSIZE\_CONTAINER", "OLE\_HANDLE", "OLE\_OPTEXCLUSIVE", \  
"OLE\_CANCELBOOL", "OLE\_ENABLEDEFAULTBOOL", "FONTSIZE", "OLE_COLOR")  
#import "olch3x8.ocx" rename_namespace("OChart3D")  
using namespace OChart3D;

If you are using both the 2D and 3D Chart, both of the #import statements above must be added.

Step 4:

Now, open the dialog class header yourDlg.h. You can add a CWnd instance to the dialog class and use it to access the chart. So, add the following to the end of the class:

CWnd m_chart;       // ComponentOne Chart

The class code in your dialog class header will look something like this:

class CChartImportDlg : public CDialog  
{  
   // Construction  
   public: CChartImportDlg(CWnd* pParent = NULL); // standard constructor  

   // Dialog Data  
   //{{AFX_DATA(CChartImportDlg)  
   enum { IDD = IDD\_CHARTIMPORT\_DIALOG };  
   // NOTE: the ClassWizard will add data members here  
   //}}AFX_DATA  

   // ClassWizard generated virtual function overrides  
   //{{AFX_VIRTUAL(CChartImportDlg)  
   protected:  
   virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support  
   //}}AFX_VIRTUAL  

   // Implementation  
   protected:  
   HICON m_hIcon;  

   // Generated message map functions  
   //{{AFX_MSG(CChartImportDlg)  
   virtual BOOL OnInitDialog();  
   afx_msg void OnSysCommand(UINT nID, LPARAM lParam);  
   afx_msg void OnPaint();  
   afx_msg HCURSOR OnQueryDragIcon();  
   //}}AFX_MSG  
   DECLARE\_MESSAGE\_MAP()  

   CWnd m_chart; //ComponentOne Chart  
};

Step 5:

This is the last step before we can begin accessing the chart properties. The CWnd must be initialized and attached to the chart window. We do this by making a call to DDX_Control() in the dialog class DoDataExchange(). The code for DoDataExchange will look like this, where IDC_CONTROL1 is the ID of the chart control on the form:

void CChartImportDlg::DoDataExchange(CDataExchange* pDX)  
{  
   CDialog::DoDataExchange(pDX);  
   DDX\_Control(pDX, IDC\_CONTROL1, m_chart); // ComponentOne  
}

Step 6:

Now, we can begin to access the chart and change settings. Keep in mind that when you are accessing the properties, it may be necessary to use the namespace identifier. This is important, because some properties appear in both the 2D and 3D chart, and the Font properties of both need to fully qualified due to the Microsoft bug mentioned earlier. The following should use the namespace identifier: IView3D_DualPtr, since it appears in both the 2D and 3D chart namespaces, if you are using both the 2D and 3D chart. For example use OChart2D::IView3D_DualPtr for the 2D chart and OChart3D::IView3D_DualPtr for the 3D chart. The Font classes should also use the namespace because of the Microsoft bug. For example use OChart2D::Font and/or OChart3D::Font regardless of whether both charts are used. To complete this example, make a few changes to the default chart properties to get a feel for how to use Chart through #import in your own projects. Add the following to the OnInitDialog() Method in your dialog cpp:

// Get an instance of the chart Dual interface.  This will  
// allow direct calls into the OCX.  
OChart2D::IChart2D\_DualPtr xchart = m\_chart.GetControlUnknown();  

// change the ChartArea background color to grey  
xchart->ChartArea->Interior->BackgroundColor = 0xc0c0c0;  

// Change to a ribbon chart by adding Depth, Elevation and Rotation.  
// In this case it is convenient to obtain a pointer to the View3D object.  
OChart2D::IView3D_DualPtr view3d = xchart->ChartArea->View3D;  

// change the view3d properties  
view3d->Depth = 20;  
view3d->Elevation = 20;  
view3d->Rotation = 20;

The entire Method will look something like this once you add the code above:

BOOL CChartImportDlg::OnInitDialog()  
{  
   CDialog::OnInitDialog();  

   // Add "About..." menu item to system menu.  

   // IDM_ABOUTBOX must be in the system command range.  
   ASSERT((IDM\_ABOUTBOX & 0xFFF0) == IDM\_ABOUTBOX);  
   ASSERT(IDM_ABOUTBOX < 0xF000);  

   CMenu* pSysMenu = GetSystemMenu(FALSE);  
   if (pSysMenu != NULL)  
   {  
      CString strAboutMenu;  
      strAboutMenu.LoadString(IDS_ABOUTBOX);  
      if (!strAboutMenu.IsEmpty())  
      {  
         pSysMenu->AppendMenu(MF_SEPARATOR);  
         pSysMenu->AppendMenu(MF\_STRING, IDM\_ABOUTBOX, strAboutMenu);  
      }  
   }  

   // Set the icon for this dialog.  The framework does this automatically  
   //  when the application's main window is not a dialog  
   SetIcon(m_hIcon, TRUE);   // Set big icon  
   SetIcon(m_hIcon, FALSE);  // Set small icon  

   // TODO: Add extra initialization here  

   // Get an instance of the chart Dual interface.  This will  
   // allow direct calls into the OCX.  
   OChart2D::IChart2D\_DualPtr xchart = m\_chart.GetControlUnknown();  

   // change the ChartArea background color to grey  
   xchart->ChartArea->Interior->BackgroundColor = 0xc0c0c0;  

   // Change to a ribbon chart by adding Depth, Elevation and Rotation.  
   // In this case it is convenient to obtain a pointer to the View3D object.  
   OChart2D::IView3D_DualPtr view3d = xchart->ChartArea->View3D;  

   // change the view3d properties  
   view3d->Depth = 20;  
   view3d->Elevation = 20;  
   view3d->Rotation = 20;  

   // alternatively, it is possible to access objects through  
   // the object model.  
   //  
   //xchart->ChartArea->View3D->Depth = 20;  
   //xchart->ChartArea->View3D->Elevation = 20;  
   //xchart->ChartArea->View3D->Rotation = 20;  

   return TRUE;  // return TRUE  unless you set the focus to a control  
}

Additional Resources

You can find sample applications based on this article, for each version of vC++, below: ChartImport_VC6 ChartImport_VC2002 ChartImport_VC2003 ChartImport_VC2005 If you don't want to use #Import, and you have vC++ 6, the following section will show you how to generate the wrapper classes.

How do I create the header (.h) and implementation (.cpp) files for Chart ActiveX?

The vC++ environment will generate the .h and .cpp wrappers for you when you create a member variable for the chart. Here is how you can get the environment to create the files: VC++ 6:

  1. Create a new vC++ project and drop a Chart (2D or 3D) control on the form.
  2. Go to View/ClassWizard from the main menu.
  3. Select the "Member Variables" tab
  4. Select the Chart Control ID in the list (IDC_CONTROL1 by default).
  5. Click the "Add Variable" button
  6. In the popup window enter a name for the Chart member variable select the "Control" category, then click Ok.
  7. A window with a list of wrappers will pop up. You can select which wrappers you want from the list, then click Ok.
  8. Any wrappers that you selected will show up in the project. You can copy the ones you need over to your existing project, or create the wrappers within your existing project provided that you create a backup copy of the existing project. There is not much of a chance that something will go wrong with an existing project, but have a backup to be safe.

VC++ .NET (2002-2005): Due to Microsoft's reduced support for ActiveX controls in VS.NET, the automatically generated wrappers are not very good. The best option is to either use the automatically generated classes form vC++ 6, or use an #Import statement to bypass the wrappers altogether. If you want to try the automatically generated classes in .NET, here is how you get them:

  1. Open or create a project with the Chart control, added to one of the project forms in design time.
  2. Right-click on the Chart, and select "Add variable."
  3. Select the Chart as the variable type, create a name for the grid variable in the "Variable name" field.
  4. Select Control in the "Category" field.
  5. If you like, you can change the .h and .cpp files to be created in the ".h" and ".cpp" fields.
  6. Click "Finish" and the .h and .cpp wrapper will be added to your project.

If you choose to use #Import statements, please be aware that there is a .NET Framework bug that can casue conflicts with stdole. For more information, please see the following Microsoft article: http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q224610&ID=KB;EN-US;Q224610#appliesto

MESCIUS inc.

comments powered by Disqus