דפים

Saturday, October 6, 2012

A few words about COM

I would really like to talk about Distributed Component Object Model (DCOM) a little, but to do that I first must talk aboutsome basic terms as Managed and Unmanaged code, COM (Component Object Model) andothers. So this post will deal with these terms while in the next post I'lltalk about DCOM and where you can use it.

So let's start at the very beginning.

In the Windows operating system you can write User mode or Kernel mode code. I will write posts about Kernel mode development in the future, but in this one I would like to discuss some basic staff about user space development.

Unmanaged code – a quick reminder

I know that it's probably not agood idea to explain what an unmanaged code is by telling you what is a managed code, but I guess that this would be the easier way to understand it.

Managed code is a Microsoft term for a code that the compilation and execution of which is managed by the CLR - Common Language Runtime. The CLR is an environment that is part of the .NET framework designed to manage the execution of programs. You may think of the CLR as the Java VM because here the code is also compiled to an intermediate language (CIL) that can executed later by the CLR that will convert it into machine code. 

There are numerous benefits that you gain from that. Probably the major one is the memory management that the CLR does for you by releasing objects that are no longer in use (managed data)and operating a Garbage Collector that eliminates memory leaks. But there are other benefits that reduce common programmers' errors. 

In unmanaged code you'll need to manage your own memory allocations, avoid memory leaks and free unused space in the memory. The library/executable that is resulted by the unmanaged code compilation is written in machine code (therefore running faster) and don't need the .NET framework installed.

There are several ways to manage an unmanaged code. One of them is exposing the required methods through COM and use the COM object from the managed code program - this is the most widely used method. A nice article about that can be found here.

BTW, The CLR is implemented as a COM server.

What is COM?

Well, we'll need more than one blog post to deeply understand what COM is, but let's try to keep it simple. For those of you that would like to deepen the understanding and learn how to use COM, I would recommend the "Introduction to COM" article by Michael Dunn in Codeproject.com – an oldie but a goodie.

COM is a standard that lets COM objects to interact with other object enabling sharing binary code across different applications. COM is a binary standard that applies after a program has been translated to binary machine code and specifies that the binary modules (libraries and executables) must be compiled to match a specific structure. 

This is the beauty of it. There is a little that is up to the programmer while the compiler does all the work in creating the COM objects that is easy to use later.

A COM object is made up of a set of data and the functions that manipulate the data. Access to an object's data is achieved exclusively through interface methods. COM requires that the only way to gain access to the methods of an interface is through a pointer to the interface.

COM also defines how objects work together over a distributed environment and has added security features to help provide system and component integrity – but more on that in the next post.

An example – WMI (WindowsManagement Instrumentation)

"WMI provides a uniform interface for any local or remote applications or scripts that obtain management data from a computer system, a network, or an enterprise."


There is lots of cool stuff you can do with WMI and if you're not familiar with it yet, I would recommend toget familiar with it (maybe I'll write a post about WMI too) but let's focus on the fact that the way to use WMI is by its COM interface. The WMI COM API enables developers to write a WMI client or an application that uses WMI information.

Let's take a look at the example from the article "GettingWMI Data from the Local Computer" in the MSDN. First it initialize the COM parameters using the CoInitializeEx() function, then some security information is passed via CoInitializeSecurity() and then we get access to the WMI COM API by using CoCreateInstance() function with the CLSID_WbemLocator object and getting the IWbemLocator pointer.

Now we can call IWbemLocatorobject's function (like ConnectServer()).

HRESULT hres;
hres =  CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        cout << "Failed to initialize COM library. Error code = 0x"
            << hex << hres <<endl;
        return 1;                  // Program has failed.
    }

    hres = CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   //Default authentication
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation 
        NULL,                        //Authentication info
        EOAC_NONE,                   // Additional capabilities
        NULL                         // Reserved
        );
               
    if (FAILED(hres))
    {
        cout << "Failed to initialize security. Error code = 0x"
            << hex << hres <<endl;
        CoUninitialize();
        return 1;                    // Program has failed.
    }

    IWbemLocator *pLoc = NULL;

    hres = CoCreateInstance(
        CLSID_WbemLocator,            
        0,
        CLSCTX_INPROC_SERVER,
        IID_IWbemLocator, (LPVOID *)&pLoc);

    if (FAILED(hres))
    {
        cout << "Failed to create IWbemLocator object."
            << " Err code = 0x"
            << hex << hres <<endl;
        CoUninitialize();
        return 1;                 // Program has failed.
    }

    IWbemServices *pSvc = NULL;
        
    hres = pLoc->ConnectServer(
         _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
         NULL,                    // User name. NULL = current user
         NULL,                    // User password. NULL = current
         0,                       //Locale. NULL indicates current
         NULL,                    // Security flags.
         0,                       // Authority (for example, Kerberos)
         0,                       // Context object
         &pSvc                    // pointer to IWbemServices proxy
         );
   
    if (FAILED(hres))
    {
        cout << "Could not connect. Error code = 0x"
             << hex << hres<< endl;
        pLoc->Release();    
        CoUninitialize();
        return 1;                //Program has failed.
    }

Nice! Isn't it?


Let's conclude this post with a nice song by Jimi Hendrix, Love or Confusion, because that's how you probably feel right now, isn't it? J

No comments:

Post a Comment