Hosting Windowed ActiveX Controls in ASP Scripts (MSChart Example).

Environment: VC6.0 SP3+, NT4.0 SP3+, Win98 SE, Windows 2000/Me/XP, IIS 3.0+ or PWS

Have you ever wondered how to display charts or any other visual ActiveX controls in a web environment without having the need for the client (the browser in this case) to download these conrols in order to display the data. The best way of doing that is by creating an image from the control's client area and saving it on disk and then having that image as a link reference to display the image on the client page like the image shown above.

Well I found a lot of controls that did that, but none of them was giving away the source code for free, so I decided to write my own because I wanted to learn and on the other hand I wanted it to be custom made to suit my needs. In this Chart Example we will create an ATL project with a single COM object to host our MSChart Control.

The assumptions for the Chart Example are:

  1. Running in a MS-Windows environment
  2. Have a web server running on the machine (IIS or PWS)
  3. Have MSChart ActiveX control registered on the system (It should come with the OS or VB or MS-Office or download it from Microsoft's web site)

There are 10 easy steps to the process:

  1. Create a new ATL COM project and name it AXHostLib



  2. Create an ActiveX Server Component Object and name it Host



  3. Create a property and call it CreateObject with only the get attribute.



  4. Create a method and call it SavePicture



  5. Create a "dummy" dialog in the resource with id IDD_DIALOG1 that will be the parent window for our MSChart control



  6. In the Host.h file add the include and the private section shown:
    #include "afxtempl.h"
     //////////////////////////////////////////////////////////////
    // CHost
    
    class ATL_NO_VTABLE CHost :
    
    private:
        CDialog* pDlg;
        CWnd* pControlWnd;
    
        CArray<IDISPATCH*, IDispatch*> m_DispatchArray;
        CArray<CDIALOG*, CDialog*> m_DialogArray;
        CArray<CWND*, CWnd*> m_ControlWndArray;
    
  7. In the Host.cpp file the includes and the two methods (CreateObject and SavePicture) look like this:
    Note:
    Notice that the SavePicture method grabs the image from the clipboard and then saves it on the disk as a GIF, using a third-party library. You can use any other code you want at that point. You can find other functions for saving the image to disk in the http://www.codeguru.com/bitmap/ or you can download the CXImage library from http://www.codeproject.com/bitmap/cximage.asp and place the source in the CXImage directory of this project's source code. Using the CXImage library the image can be saved in one of the following formats PNG, BMP, JPG, TIFF or GIF. There are also other third party libraries that can be used under the GNU aggreement like the PaintLib found at http://www.paintlib.de/paintlib/.

    #include "comdef.h"
    #include "CXImage/CXImage/ximagif.h"
    //-------------------------------------------------------
    STDMETHODIMP CHost::get_CreateObject( BSTR ObjectID,
                                          long Width, 
                                          long Height, 
                                          IDispatch **pVal)
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState())
    
        _bstr_t tmpbstr = _bstr_t(ObjectID, TRUE);
        CString ObjID = (char*) tmpbstr;
    
        HRESULT hr;
        IUnknown* pUnknown = NULL;
    
        //Create rect structure according to the size we want
        RECT rect;
        rect.left = 0;
        rect.top = 0;
        rect.bottom = Height;
        rect.right = Width;
    
        Create the dialog as a modeless one
        pDlg =  new CDialog();
        pDlg->Create(IDD_DIALOG1, NULL);
    
        //Create the window from an ActiveX Control with 
        // parent the dialog
        pControlWnd =  new CWnd();
        pControlWnd->CreateControl( ObjID,
                                       NULL,
                                       WS_VISIBLE,
                                       rect,
                                       pDlg,
                                       1);
    
        // Get the IUnknown in order to query the 
        // IDispatch and return it to the ASP page
        pUnknown = pControlWnd->GetControlUnknown();
    
        if (m_bOnStartPageCalled)
            hr = pUnknown->QueryInterface( IID_IDispatch,
                                              (void**) pVal);
        else
            *pVal = 0;
    
        //Save all the pointers for later clean up
        m_DispatchArray.Add(*pVal);
        m_DialogArray.Add(pDlg);
        m_ControlWndArray.Add(pControlWnd);
    
        return hr;
    }
    //------------------------------------------------------
    STDMETHODIMP CHost::SavePicture(BSTR filename)
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState())
    
        _bstr_t tmpbstr = _bstr_t(filename, TRUE);
        CString name = (char*) tmpbstr;
    
        //paste
        HANDLE hBitmap = NULL;
        if (OpenClipboard(NULL))
            hBitmap = GetClipboardData(CF_DIB);
    
        if (hBitmap)
        {
            CxImage image(hBitmap);
            image.DecreaseBpp(8);
            image.SaveFile(name, CXIMAGE_FORMAT_GIF);
        }
        CloseClipboard();
    
        return S_OK;
    }
  8. In the InitInstance of the Application in the AXHostLib.cpp add the the following line:
    AfxEnableControlContainer();
  9. Create the ASP page now and add the following:
    Note:
    Make sure you change the line that says l_conn.Open to point to the correct directory where the database file is.
      dim Host
      dim Chart
      dim l_conn
      'Create our COM Object
      set Host = Server.CreateObject("AXHostLib.Host")
      Set Chart = Host.CreateObject("MSChart20Lib.MSChart", 600, 350)
    
      'Create the data connection for our chart
      set l_conn = Server.CreateObject("ADODB.Connection")
      l_conn.Open "PROVIDER=Microsoft.Jet.OLEDB.3.51;Data
       Source=c:/inetpub/wwwroot/Stocks/data/MSFT.mdb;"
    
      dim l_rec
      dim l_sqlStatement
      set l_rec = Server.CreateObject("ADODB.Recordset")
      l_sqlstatement = "SELECT close FROM Quotes order by date asc"
      l_rec.Open l_sqlstatement, l_conn, 2, 3
    
      'Set the Chart's properties and DataSource
      set Chart.DataSource = l_rec
      Chart.ChartType = 3
      Chart.AllowSelections = 0
      Chart.ShowLegend = 0
      dim serX
      For Each serX In Chart.Plot.SeriesCollection
        serX.Pen.Width = 1
        serX.Pen.VtColor.Automatic = 0
        serX.Pen.VtColor.Red = 0
        serX.Pen.VtColor.Green = 0
        serX.Pen.VtColor.Blue = 255
      Next
      Set XAxis = Chart.Plot.Axis(0)
      'Scale of the ticks
      XAxis.CategoryScale.Auto = 0
      XAxis.CategoryScale.DivisionsPerLabel = 
                                   Chart.RowCount / 10
      XAxis.CategoryScale.DivisionsPerTick = 
                                   Chart.RowCount / 10
    
      'Close connection and recordset
      l_rec.Close
      l_conn.Close
    
      'Save the image
      Chart.EditCopy
      Host.SavePicture "c:/inetpub/wwwroot/Stocks/data/image.gif"
    

Links

CXImage Library with documentation and examples of how to use it.
PaintLib Library with documentation and examples of how to use it.
(The MSChart Example here uses only the GIF format from the CXImage Library to save the image on disk)

Downloads

Download demo project - 261 Kb
Download source - 283 Kb


Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The impact of a data loss event can be significant. Real-time data is essential to remaining competitive. Many companies can no longer afford to rely on a truck arriving each day to take backup tapes offsite. For most companies, a cloud backup and recovery solution will eliminate, or significantly reduce, IT resources related to the mundane task of backup and allow your resources to be redeployed to more strategic projects. The cloud - can now be comfortable for you – with 100% recovery from anywhere all …

  • The latest release of SugarCRM's flagship product gives users new tools to build extraordinary customer relationships. Read an in-depth analysis of SugarCRM's enhanced ability to help companies execute their customer-facing initiatives from Ovum, a leading technology research firm.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds