Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Beginner tutorial for writing simple COM/ATL DLL

0.00/5 (No votes)
6 Nov 2004 4  
An article touching simple issues like events, methods and properties.

Introduction

During discussion on forums, I come across many people who want to write COM/ATLDLL, but don�t know how to create properties, methods or raise events from Component or strive for fundamental knowledge to create them. In this Article, I am going to write a simple, ATL DLL step by step using VC++ 6.0 and demonstrate creation and usage of property, method and event.

Convention Used

  • Symbol �-->� means Author Comments.
  • Symbol �|� means Menus Operation, i.e., File|New means clicking new item of File Menu.

Let�s Start

Since I am writing a Beginner Article, I have included as many screen shots to explain the creation of COM DLL and let me explain that to you step by step.

  1. Open Visual Studio 6.0 and click Menu Item File|NEW to get this Dialog Box.
    Fiqure 1: Visual Studio App Wizard
    Sample screenshot
  2. Now select ATL COM AppWizard and give a project name SimpleAtlCom and click OK to Accept Project Setting, and in next step you will see this dialog box.
    Figure 2 ATL/COM App Wizard
    figure 2
  3. Click Finish to Accept Project Setting.

    These above written two steps will create a blank COM DLL project for you.

  4. Now from menu Insert|NEW ATL Object... , add an ATL object to project. You will see this figure when you click the above menu item.
    figure 3:ATL Object Wizard
    figure 3
  5. Select the Object|Simple object and click Next, then you will see this Property page. Take a view of the following figure.
    Figure 4: ATL Object Wizard after selection of SimpleAtl Object.
    figure4
  6. Here ( in fig. 4 ) give the Short Name as SimpleObj and you will see other fields in this dialog box get self generated.
    Figure 5 :Showing the Attribute of ATL Object
    figure 5
  7. In fig. 5, let me explain every thing.
    • First you see the Threading Model; here I have selected Compiler default which is apartment as most of other applications using our component is comfortable with this model.
    • Second you see Interface, again I have selected the Wizard Default to Dual (the benefit of using dual interface is that, you can use it in scripting language also).
    • Leave the topics of Aggregation and free thread Marshaler, as they are too advanced to be used in this article.
    • Now look at ISupportErrorInfo, this is provided to send rich textual information back to Client Application which is using our Interface. As we are not going to send any Error Information back to Client, I have left this Check Box unchecked.
    • Last but not the least, for invoking event from component, you need support of ConnectionPoint Interface. So check the box for supporting the connection point, click OK to Add the Object.
  8. Now in your project, a new IDL file is added (simpleAtlCom.idl). Here, take a look at IDL file, how�s it look like:
    // SimpleAtlCom.idl : IDL source for SimpleAtlCom.dll
    
    
    //
    
    
    // This file will be processed by the MIDL tool to
    
    
    // produce the type library (SimpleAtlCom.tlb) and marshalling code.
    
    
    import "oaidl.idl";
    
    import "ocidl.idl";
    
    // Above two File are define the IDispatch Inteface etc.
    
    
    [
    
    object,
    
    uuid(10CDF249-A336-406F-B472-20F08660D609),
    
    // Unique Id OF Object
    
    
    dual,
    
    // State our Interface is Dually Suported
    
    
    helpstring("ISimpleObj Interface"),
    
    pointer_default(unique)
    
    ]
    
    // Our Empty Interface
    
    
    interface ISimpleObj : IDispatch
    
    {
    
    };
    
    [
    
    uuid(8B1C3F79-07BA-44F8-8C47-AE2685488DFA),
    
    version(1.0),
    
    // our Library Name
    
    
    helpstring("SimpleAtlCom 1.0 Type Library")
    
    ]
    
    library SIMPLEATLCOMLib
    
    {
    
        importlib("stdole32.tlb");
    
        importlib("stdole2.tlb");
    
        [
    
        uuid(9B5BC0F8-7421-4C46-AA5F-539ECCAFCB82),
    
        helpstring("_ISimpleObjEvents Interface")
    
       ]
    
       // Disinterface Provides support for raising events,
    
       //as I already told you about that above
    
       dispinterface _ISimpleObjEvents
    
       {
    
           properties:
      
           methods:
     
        };
    
       [
    
       uuid(27BF0027-BECC-4847-AF91-99652BCE9791),
    
       helpstring("SimpleObj Class")
    
       ]
    
       // Our object base class where actual coding of our Property 
    
       //and Event resides
    
        coclass SimpleObj
    
        {
    
            [default] interface ISimpleObj;
    
             [default, source] dispinterface _ISimpleObjEvents;
    
        };
    
    };
  9. Now add property and method to our Interface. Let's make a simple application based on class application. Any way, do you know what is a property and a method. If not, here is brief description about them. Method is the name given to a function in interface and property to variable. But remember one thing, every thing in COM/ATL is based on function, one major difference between property and method is that, you can make a property read only (means you can only get data from property but you can�t put them). Now let's get back to our application.
  10. Now put three methods, both Get and Put and one method in our interface. Now you are going to ask how and where to put them. Right click on your interface. You will get the option for putting both the method and property. For clarity, let's take a look on these pictures.
    Figure 6: Showing Popup menu Figure 7: Showing Property Wizard
    figure 6 figure7
  11. Figure 6 shows you from where you can add the properties and methods to your interface. Now as in figure 7, you can add three properties, Name, ATLMarks and ComMarks and one method Calculate and for raising, I will tell you at the end. After adding that, your interface looks like this:
    interface ISimpleObj : IDispatch
    // Our base interface
    
    {
    
      [propget, id(1), helpstring("property Name")] 
           HRESULT Name([out, retval] BSTR *pVal);
    
      [propput, id(1), helpstring("property Name")] 
           HRESULT Name([in] BSTR newVal);
    
      [propget, id(2), helpstring("property ATLMarks")] 
           HRESULT ATLMarks([out, retval] short *pVal);
    
      [propput, id(2), helpstring("property ATLMarks")] 
           HRESULT ATLMarks([in] short newVal);
    
      [propget, id(3), helpstring("property COMMarks")] 
           HRESULT COMMarks([out, retval] short *pVal);
    
      [propput, id(3), helpstring("property COMMarks")] 
           HRESULT COMMarks([in] short newVal);
    
      [id(4), helpstring("method Calculate")] 
          HRESULT Calculate();
    
    };
  12. Now you will see function for every properties and methods in you class CSimpleObj. Before going for actual coding, I think you want to know propget, propput and method in above Interface.
    • Propget � stands for property for getting the value from Component.
    • PropPut�stands for property for putting property to Component. This can be optional and if you remove it, this can make your property readonly.
    • Method�simple function to perform some calculation.
    • [in] --- means data is going in or you are putting some value to Component.
    • [out,retval] --- notation states that argument using this will return with data.
    • HRESULT --- Standard Error reporting variable.
  13. Now add some useful variables in the class that will take care of above properties. Add char Name[100], short AtlMarks and short COMMarks in your CSimpleObj class and I have coded the rest of the simple class for you. Let's see and explain each function, I have included. One more property viz total, which will return the total. Still we don�t implement Events.

    Here is our SimpleObj class code.

    STDMETHODIMP CSimpleObj::get_Name(BSTR *pVal)
    {
         // return Name of Student
    
         CComBSTR bstStr(this->Name);
         *pVal=bstStr.Detach();
         return S_OK;
    }
    
    STDMETHODIMP CSimpleObj::put_Name(BSTR newVal)
    {
         // put Name of Student
    
    
         ::wcstombs(this->Name,newVal,99);
         return S_OK;
    }
    
    STDMETHODIMP CSimpleObj::get_ATLMarks(short *pVal)
    {
         //return ATL marks
    
    
        *pVal=this->ATLMarks;
    
        return S_OK;
    }
    
    STDMETHODIMP CSimpleObj::put_ATLMarks(short newVal)
    {
        // return Put of marks of atl
    
    
        this->ATLMarks=newVal;
    
        return S_OK;
    }
    
    STDMETHODIMP CSimpleObj::get_COMMarks(short *pVal)
    {
        // get the marks for COM
    
    
        *pVal=this->COMMarks;
        return S_OK;
    }
    
    STDMETHODIMP CSimpleObj::put_COMMarks(short newVal)
    {
        //put marks for COM
    
    
        this->COMMarks=newVal;
        return S_OK;
    }
    
    STDMETHODIMP CSimpleObj::get_Total(short *pVal)
    {
        //return total number of marks
    
        *pVal=this->m_iTotalMarks;
        return S_OK;
    }
    
    STDMETHODIMP CSimpleObj::Calculate()
    {
        // Calculate total number of marks and store it total number variable
    
        this->m_iTotalMarks=this->ATLMarks+this->COMMarks;
        return S_OK;
    }
    
  14. Now compile and build the SimpleAtlCom.dll using BUILD|BUILD SimpleATLCom.dll, and I think, you successfully get yourself a SimpleATLCom.dll.
  15. Now develop a simple Visual Basic Project for it. I have created a sample UI for the above component, let's take a look on it.
    Figure 8: Visual Basic Interface for above Com DLL
    figure8
  16. Now let's go for coding side, first add reference of our com DLLs to project. You can find option for it in PROJECT|REFRENCES of Visual Basic IDE. After clicking that you will get a dialog box like this, just find our SimpleAtlCom library in it and check the box against it. This will refer that DLL in your project (it is same as including a header file in C++ project) and press OK. This is how the dialog application looks like.
    Figure 9 :Reference Dialog Box of Visual Basic IDE
    figure9
  17. Now let's look at the backend coding of VB application.
    'Our Component Object
    
    Private Obj As SIMPLEATLCOMLib.SimpleObj
    
    Private Sub cmdPutValue_Click()
    
    'give memory to Com object
    
    Set Obj = New SIMPLEATLCOMLib.SimpleObj
    
    'put atl marks in component
    
    Obj.ATLMarks = txtPutATL
    
    'put com marks
    
    Obj.COMMarks = Me.txtPutCom
    
    'put Name
    
    Obj.Name = Me.txtPutName
    
    End Sub
    
    Private Sub cmdGetValue_Click()
     'calculate the marks
    
      Obj.Calculate
    
     'put atl marks in component
    
      Me.txtGetAtl = Obj.ATLMarks
    
     'put com marks
    
      Me.txtGetCom = Obj.COMMarks
    
     'put Name
    
      Me.txtGetName = Obj.Name
    
     'get total marks and display it on the Component
    
      Me.txtTotalMarks = Obj.Total
    
    End Sub
  18. Now before going for events, let's see test running of our application. Here it is:
    Figure 10:First Run of Our Com DLL
    figure 10
  19. I think, till now nobody have faced any problem. I am getting above. Now take a look at events and how to create them and raise them. You can see an Interface name _ISimpleObjEvents. This is disinterface created by APP Wizard which provides support for events. You can see a prefix '_' (underscore). This underscore notifies MIDL (Microsoft IDL compiler) that this interface is disinterface and don�t make it part of TLB files. Now right click on this interface and add a method say, Void TOTAL([in]short marks) as shown in this fiqure:
    Figure 11: Adding Method to DisInterface
    figure 11
  20. Now right Click on your CSimpleObj class and click on Implement Connection Point Option. You will see this figure, check on _ISimpleObjEvents check box and Click OK. Voila! The CProxy_ISimpleObjEvents class is get added to your project. This is the proxy class that will fire event for you. You can see that, it contains the function VOID Fire_TotalMarks(SHORT TotalMarks) which is a proxy function and raises events. Oh! I forgot, take a look at the picture for Connection Point implementation.
    Fiqure 12: Adding Connection Point
    figure 12
  21. Now event is added to your class. Let's modify the CSimpleObj::Calculate().

    Now new CSimpleObj::Calculate() looks like this:

    STDMETHODIMP CSimpleObj::Calculate()
    {
    
         //add Marks
    
        this->m_iTotalMarks=this->ATLMarks + this->COMMarks;
    
        // when you use this pointer ,Fire_Totalmarks support 
    
        //is added to your class
    
        // after you implement the Connection points 
    
        // This event will fire the Total though event to Client
    
        
        this->Fire_TotalMarks(this->m_iTotalMarks);
    
        return S_OK;
    }
  22. Now let's modify our Visual Basic application to handle events.

    Change

    Private Obj As SIMPLEATLCOMLib.SimpleObj

    to

    Private withevents Obj As SIMPLEATLCOMLib.SimpleObj

    This helps us to implement events, look this figure for more clarity.

    Figure 14:Visual Basic, Adding Event to Project
    figure 14
  23. Now look at code for implementation of events, as TotalMarks comes from event, just add a line to show total marks. So our event code looks like:
    Private Sub Obj_TotalMarks(ByVal TotalMarks As Integer)
        'Display the MessageBox displaying Total Marks
    
        MsgBox "total marks " & TotalMarks
    
    End Sub
    
  24. Now test and run the application. Here it is the message box showing the event.
    Figure 15: Our Fully Functionable DLL and Application
    figure 15

Download Codes Includes

Source Code Includes

  1. SimpleAtlCom.dll (with source code).
  2. Test Project in Visual Basic.

Test Project Includes

  1. Compiled Test Application.
  2. Compiled SimpleAtlCom.dll.

Using of Demo Application

If you like, use the Com DLL and Test application first. Don�t forget to register Com DLL i.e., SimpleAtlCom.dll, to your computer. You can use this command line to register the Component.

Drive:> %sys%regsvr32 SimpleAtlCom.dll

Author Comment

I tried my level best to tell each and every simple aspect of com DLL. If it is missing something, feel free to contact me.

Special Thanks

  • To My Mother and Father.
  • To CodeProject.com providing platform for Programmer Interaction.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here