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

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read