CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6
  1. #1
    Join Date
    Oct 2010
    Posts
    5

    Developing a COM object using ATL COM Wizard

    Hi, Need some Help

    I've been developing an object which basically is a X-Y plot that can be used later in any active X or COM container. I am using Visual C++ 6.0 and Windows GDI, am not using MFC.

    I can build the project and test it on the ActiveX test container and it looks to be working ok. However when I put the control in a different container (Indusoft which is a HMI software) it runs ok but after a few hours, the control stops drawing itself, so it looks like some resource or memory consumption is happening there.

    I can provide copy of the source code to see if anyone can help.

    Thanks, jhrodriguez08
    Last edited by jhrodriguez08; October 12th, 2010 at 12:03 PM.

  2. #2
    Join Date
    Oct 2010
    Posts
    5

    Re: Developing a COM object using ATL COM Wizard

    Just attaching part of the code

    // CompMap.h : Declaration of the CCompMap

    #ifndef __COMPMAP_H_
    #define __COMPMAP_H_

    #include "resource.h" // main symbols
    #include <atlctl.h>


    /////////////////////////////////////////////////////////////////////////////
    // CCompMap
    class ATL_NO_VTABLE CCompMap :
    public CComObjectRootEx<CComSingleThreadModel>,
    public IDispatchImpl<ICompMap, &IID_ICompMap, &LIBID_MAP2Lib>,
    public CComControl<CCompMap>,
    public IPersistStreamInitImpl<CCompMap>,
    public IOleControlImpl<CCompMap>,
    public IOleObjectImpl<CCompMap>,
    public IOleInPlaceActiveObjectImpl<CCompMap>,
    public IViewObjectExImpl<CCompMap>,
    public IOleInPlaceObjectWindowlessImpl<CCompMap>,
    public IConnectionPointContainerImpl<CCompMap>,
    public IPersistStorageImpl<CCompMap>,
    public ISpecifyPropertyPagesImpl<CCompMap>,
    public IQuickActivateImpl<CCompMap>,
    public IDataObjectImpl<CCompMap>,
    public IProvideClassInfo2Impl<&CLSID_CompMap, &DIID__ICompMapEvents, &LIBID_MAP2Lib>,
    public IPropertyNotifySinkCP<CCompMap>,
    public CComCoClass<CCompMap, &CLSID_CompMap>
    {
    public:
    CCompMap()
    {
    m_bWindowOnly = TRUE;
    }

    DECLARE_REGISTRY_RESOURCEID(IDR_COMPMAP)

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    BEGIN_COM_MAP(CCompMap)
    COM_INTERFACE_ENTRY(ICompMap)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IViewObjectEx)
    COM_INTERFACE_ENTRY(IViewObject2)
    COM_INTERFACE_ENTRY(IViewObject)
    COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
    COM_INTERFACE_ENTRY(IOleInPlaceObject)
    COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
    COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
    COM_INTERFACE_ENTRY(IOleControl)
    COM_INTERFACE_ENTRY(IOleObject)
    COM_INTERFACE_ENTRY(IPersistStreamInit)
    COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
    COM_INTERFACE_ENTRY(IConnectionPointContainer)
    COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
    COM_INTERFACE_ENTRY(IQuickActivate)
    COM_INTERFACE_ENTRY(IPersistStorage)
    COM_INTERFACE_ENTRY(IDataObject)
    COM_INTERFACE_ENTRY(IProvideClassInfo)
    COM_INTERFACE_ENTRY(IProvideClassInfo2)
    END_COM_MAP()

    BEGIN_PROP_MAP(CCompMap)
    PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
    PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
    // Example entries
    // PROP_ENTRY("Property Description", dispid, clsid)
    // PROP_PAGE(CLSID_StockColorPage)
    END_PROP_MAP()

    BEGIN_CONNECTION_POINT_MAP(CCompMap)
    CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
    END_CONNECTION_POINT_MAP()

    BEGIN_MSG_MAP(CCompMap)
    CHAIN_MSG_MAP(CComControl<CCompMap>)
    DEFAULT_REFLECTION_HANDLER()
    MESSAGE_HANDLER(WM_ERASEBKGND, OnErase)
    END_MSG_MAP()
    // Handler prototypes:
    // LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
    // LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
    // LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);



    // IViewObjectEx
    DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)

    // ICompMap
    public:

    float m_y4;
    float m_y3;
    float m_y2;
    float m_y1;
    float m_y0;
    float m_x4;
    float m_x3;
    float m_x2;
    float m_x1;
    float m_x0;
    float m_margin;
    float m_hpsim;
    float m_hpmax;
    float m_op;
    float m_sp;
    float m_sll;

    bool m_update;

    private:

    POINT SLL[5],CLL[5],OPT[5],gridline[2];

    long pyxels_tv,pyxels_th,pyxels_h,pyxels_v;

    int i,op_pyxel,hp_pyxel;





    STDMETHOD(Update)(float x0, float x1, float x2, float x3, float x4, float y0, float y1, float y2, float y3, float y4,float margin, float hpmax,float hpsim,float op,float sp,float sll);


    LRESULT OnErase(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
    return(LRESULT)1;
    }








    HRESULT OnDraw(ATL_DRAWINFO& di)
    {

    RECT rc;

    HPEN graypen,bluepen,redpen,greenpen,yellowpen;

    HBRUSH blackbrush,yellowbrush,hbrBkGnd;

    HDC hdcMem;
    HBITMAP hbmMem,hbmOld;





    //Este codigo me costo una bola depurar Jose Rodriguez. Las siguientes lineas
    //son las famosas lineas antifliqueo. Basicamente se copia un buffer completo
    //que contiene el area de dibujo con todas las caracteristicas del area real
    //este buffer apunta al device context en memoria hdcMem
    //El manejador de mensaje de windows WM_ERASEBKGND se bloquea para evitar que
    //borre el background
    //El background lo borramos en el device context virtual
    //Luego realizamos el dibujo sobre el area que es apuntada por hdcMem
    //Al final se copia el bitmap usando BitBlt
    //una vez que se copia la ventana se actualiza con el nuevo dibujo
    //sin perder el background.

    rc = *(RECT*)di.prcBounds;

    hdcMem=(HDC)CreateCompatibleDC(di.hdcDraw);

    hbmMem=(HBITMAP)CreateCompatibleBitmap(di.hdcDraw,rc.right,rc.bottom);

    hbmOld=(HBITMAP)SelectObject(hdcMem,hbmMem);

    hbrBkGnd=(HBRUSH)CreateSolidBrush(COLOR_WINDOW);

    SelectObject(hdcMem,hbrBkGnd);

    FillRect(hdcMem,&rc,hbrBkGnd);

    DeleteObject(hbrBkGnd);


    //Plotting the grid, Ploteando la grilla Jose Rodriguez 10/05/10



    // Let's build a grid....Let's get the total horizontal and vertical pyxels


    pyxels_h=rc.right/10;
    pyxels_v=rc.bottom/10;
    pyxels_th=rc.right;
    pyxels_tv=rc.bottom;



    //This code creates a blackbrush so we can paint the background black

    blackbrush=(HBRUSH)CreateSolidBrush(RGB(0,0,0));

    SelectObject(hdcMem,blackbrush);

    //Our black rectangle is drawn on the device context in memory

    Rectangle(hdcMem, rc.left, rc.top, rc.right, rc.bottom);

    //A gray pen will be used to plot the grid lines

    graypen=CreatePen(PS_DOT,1,RGB(128,128,128));

    SelectObject(hdcMem,graypen);

    int nBkmode=SetBkMode(hdcMem,TRANSPARENT);

    //First we plot the vertical lines

    for (i=1;i<10;i++)

    {
    gridline[0].x=i*pyxels_h;
    gridline[0].y=0;
    gridline[1].x=i*pyxels_h;
    gridline[1].y=pyxels_th;
    Polyline(hdcMem, gridline,2);

    }

    //Secondly we plot the horizontal lines

    for (i=1;i<10;i++)

    {
    gridline[0].x=0;
    gridline[0].y=i*pyxels_v;
    gridline[1].x=pyxels_tv;
    gridline[1].y=i*pyxels_v;
    Polyline(hdcMem, gridline,2);

    }


    //Once the grid is plotted the pen is deleted as well as the brush.

    DeleteObject(blackbrush);

    DeleteObject(graypen);


    //A red pen is used to draw the surge limit line

    redpen=CreatePen(PS_SOLID,2,RGB(255,0,0));

    SelectObject(hdcMem,redpen);

    //x points are expressed in pyxels, i.e. x=20% is converted to
    //20*pyxels_t/100, so when pyxels_t=240, then x will be displaced 48 pyxels

    //y points are expressed in pyxels related to Hpsim Max

    if (m_hpmax==0) //prevents cero division
    m_hpmax=1;



    SLL[0].x=m_x0;
    SLL[0].y=pyxels_tv-(m_y0*pyxels_tv/m_hpmax);
    SLL[1].x=m_x1*pyxels_th/100;
    SLL[1].y=pyxels_tv-(m_y1*pyxels_tv/m_hpmax);
    SLL[2].x=m_x2*pyxels_th/100;
    SLL[2].y=pyxels_tv-(m_y2*pyxels_tv/m_hpmax);
    SLL[3].x=m_x3*pyxels_th/100;
    SLL[3].y=pyxels_tv-(m_y3*pyxels_tv/m_hpmax);
    SLL[4].x=m_x4*pyxels_th/100;
    SLL[4].y=pyxels_tv-(m_y4*pyxels_tv/m_hpmax);

    Polyline(hdcMem,SLL,5);

    DeleteObject(redpen);

    greenpen=CreatePen(PS_SOLID,2,RGB(0,255,0));

    SelectObject(hdcMem,greenpen);

    //Control limit line is the same thing adding the margin

    CLL[0].x=(m_x0+m_margin)*pyxels_th/100;
    CLL[0].y=pyxels_tv-(m_y0*pyxels_tv/m_hpmax);
    CLL[1].x=(m_x1+m_margin)*pyxels_th/100;
    CLL[1].y=pyxels_tv-(m_y1*pyxels_tv/m_hpmax);
    CLL[2].x=(m_x2+m_margin)*pyxels_th/100;
    CLL[2].y=pyxels_tv-(m_y2*pyxels_tv/m_hpmax);
    CLL[3].x=(m_x3+m_margin)*pyxels_th/100;
    CLL[3].y=pyxels_tv-(m_y3*pyxels_tv/m_hpmax);
    CLL[4].x=(m_x4+m_margin)*pyxels_th/100;
    CLL[4].y=pyxels_tv-(m_y4*pyxels_tv/m_hpmax);

    Polyline(hdcMem,CLL,5);

    DeleteObject(greenpen);


    bluepen=CreatePen(PS_DOT,1,RGB(0,255,255));

    SelectObject(hdcMem,bluepen);

    //The optrack uses the sp minus the sll actual

    OPT[0].x=(m_x0+m_sp-m_sll)*pyxels_th/100;
    OPT[0].y=pyxels_tv-(m_y0*pyxels_tv/m_hpmax);
    OPT[1].x=(m_x1+m_sp-m_sll)*pyxels_th/100;
    OPT[1].y=pyxels_tv-(m_y1*pyxels_tv/m_hpmax);
    OPT[2].x=(m_x2+m_sp-m_sll)*pyxels_th/100;
    OPT[2].y=pyxels_tv-(m_y2*pyxels_tv/m_hpmax);
    OPT[3].x=(m_x3+m_sp-m_sll)*pyxels_th/100;
    OPT[3].y=pyxels_tv-(m_y3*pyxels_tv/m_hpmax);
    OPT[4].x=(m_x4+m_sp-m_sll)*pyxels_th/100;
    OPT[4].y=pyxels_tv-(m_y4*pyxels_tv/m_hpmax);

    Polyline(hdcMem,OPT,5);

    DeleteObject(bluepen);

    // When finished plotting lines then we
    // Then we create an object to plot the operating point.


    yellowpen=CreatePen(PS_SOLID,2,RGB(255,255,0));

    SelectObject(hdcMem,yellowpen);

    yellowbrush=CreateSolidBrush(RGB(255,255,0));

    SelectObject(hdcMem,yellowbrush);

    op_pyxel=m_op*pyxels_th/100;

    hp_pyxel=m_hpsim*pyxels_tv/m_hpmax;

    Rectangle(hdcMem,op_pyxel,pyxels_tv-hp_pyxel,op_pyxel+5,pyxels_tv-hp_pyxel+5);

    DeleteObject(yellowbrush);

    //Finally when everything was done in them memory device context
    //we copy all to the actual device context

    BitBlt(di.hdcDraw,0,0,rc.right,rc.bottom,hdcMem,0,0,SRCCOPY);

    SelectObject(hdcMem,hbmOld);

    DeleteObject(hbmMem);

    DeleteDC(hdcMem);

    DeleteDC(di.hdcDraw);

    //hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
    //hOldBrush = (HBRUSH)SelectObject(di.hdcDraw, hBrush);
    //Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
    //SelectObject(di.hdcDraw, hOldBrush);

    //LPCTSTR pszText = _T("Windows 32 & CE Map");
    //DrawText(di.hdcDraw, pszText, -1, &rc, DT_TOP | DT_VCENTER | DT_SINGLELINE);



    return S_OK;
    }
    };

    #endif //__COMPMAP_H_

  3. #3
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Developing a COM object using ATL COM Wizard

    Before deleting each created GDI object you need it be unselected. Unselection is performed by selecting original dc resource (the one returned by SelectObject while selecting new resource).

    BTW, please do not neglect using CODE tags.
    Best regards,
    Igor

  4. #4
    Join Date
    Oct 2010
    Posts
    5

    Re: Developing a COM object using ATL COM Wizard

    Hi Igor,

    Thanks for your reply. I am just getting my feets wet using GDI, I would really appreciate if you can show me how to unselect (let's say the pen or the brush) before deleting them.

    I am more of a controls engineer developing an utility for turbo machinery controls, this object represents a compressor map.

    Best regards, Jose

  5. #5
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Developing a COM object using ATL COM Wizard

    Sure, no problem:
    Code:
    //A gray pen will be used to plot the grid lines
    
    graypen=CreatePen(PS_DOT,1,RGB(128,128,128));
    
    HGDIOBJ oldPen = SelectObject(hdcMem,graypen); // selecting new resource to dc
    
    . . .
    SelectObject(hdcMem, oldPen);  // unselecting greypen before destruction
    
    DeleteObject(graypen);
    And please make sure you delete everything you create.
    Best regards,
    Igor

  6. #6
    Join Date
    Oct 2010
    Posts
    5

    Re: Developing a COM object using ATL COM Wizard

    Hello Igor,

    I figured out last night and I actually coded like you showed me today, So I left the object running overnight and it worked just fine.

    I appreciate your help.

    PS: Second challenge is making this object available for Windows CE 4.0 and 4.1

    Best regards, Jose

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured