24.1 Creating an ATL-Based COM Component

 <  Day Day Up  >  

You want to create a COM object using Visual C++ .NET and ATL .


Technique

To create a simple COM object, select the ATL Project template from the list of Visual C++ project templates. The object created in this recipe serves as a bridge to the Windows command interpreter ( cmd.exe ), allowing a .NET object to send commands as is done when running within a command console window. Recall that Chapter 16, "ASP.NET," created an ASP.NET application that provided this functionality, albeit limited, through a browser interface to a remote server.

After the project is created, you have to create the main COM object that will be used by a .NET application. Select Project, Add Class from the main menu, select the ATL Simple Object template and give the object a name in the Short Name field. For this project, we use the name CommandCom . Additionally, click on the Options tab and place a check mark in the Connection Points option. This move allows the COM object to fire events that will be handled within the .NET application created in later recipes.

At this point, you have a fully functional COM object that can be instantiated by a COM-aware language. Its functionality is severely limited, however, without any defined methods or properties. Within the Class View window, right-click on the ICommandCom interface and select the Add Method menu item. You must add this method to the ICommandCom interface rather than the CCommandCom class if you want to ensure that .NET applications can call the method. You'll notice that the return type for the method is disabled. This disabling is by design because all COM methods return a HRESULT data type, which is a 32-bit error code. Recipe 24.6, "Handling HRESULT Errors," provides further explanation of HRESULT return values. After giving the method a name ”we use Run ”you have to add any necessary parameters. A parameter can be marked as an in , out , or retval parameter type. These types sound just like their names : an in parameter is a value passed in by the callee, and the out and retval parameters are allocated and returned by the COM object. Additionally, retval circumvents the issue with return values because all COM methods (except one, but that's a different story) return HRESULT s.

The first parameter to the Run method is an in parameter whose data type is BSTR . A BSTR is known as a basic string, which internally is a wide character (two bytes per character) with a preceding value denoting its length. The second parameter is a retval parameter whose data type is BSTR* , denoting a pointer to a BSTR . Once the method is created, the Integrated Development Environment (IDE) opens the corresponding .cpp file at the location of the method, allowing you to add its definition, which appears in Listing 24.1.

Listing 24.1 COM Object Method Implementation
 #include "stdafx.h" #include "CommandCom.h" #include ".\commandcom.h" #include <atlfile.h> #include <atlsafe.h> void GetResult( LPTSTR fileName, BSTR* Result ) {     USES_CONVERSION;     CAtlFile file;     ULONGLONG len;     LPBYTE lpBuffer;     // read file into buffer     HRESULT hr = file.Create( fileName, FILE_SHARE_READ, 0, OPEN_EXISTING );     hr = file.GetSize( len );     lpBuffer = new BYTE[len];     hr = file.Read( lpBuffer, len );     file.Close();     *(lpBuffer+len) = ' 
 #include "stdafx.h" #include "CommandCom.h" #include ".\commandcom.h" #include <atlfile.h> #include <atlsafe.h> void GetResult( LPTSTR fileName, BSTR* Result ) { USES_CONVERSION; CAtlFile file; ULONGLONG len; LPBYTE lpBuffer; // read file into buffer HRESULT hr = file.Create( fileName, FILE_SHARE_READ, 0, OPEN_EXISTING ); hr = file.GetSize( len ); lpBuffer = new BYTE[len]; hr = file.Read( lpBuffer, len ); file.Close(); *(lpBuffer+len) = '\0'; // set return value *(Result) = SysAllocString( T2OLE((LPTSTR)lpBuffer) ); return; } STDMETHODIMP CCommandCom::Run(BSTR Cmd, BSTR* Output) { USES_CONVERSION; CString finalCmd; finalCmd.Format( "%s 1<&2 >\"%s\"", OLE2T(Cmd), mTempFileName ); system( finalCmd ); GetResult( mTempFileName, Output ); return S_OK; } 
'; // set return value *(Result) = SysAllocString( T2OLE((LPTSTR)lpBuffer) ); return; } STDMETHODIMP CCommandCom::Run(BSTR Cmd, BSTR* Output) { USES_CONVERSION; CString finalCmd; finalCmd.Format( "%s 1<&2 >\"%s\"", OLE2T(Cmd), mTempFileName ); system( finalCmd ); GetResult( mTempFileName, Output ); return S_OK; }

The Run method definition simply constructs a new command, which does a little stream redirection to place the results into a file. The GetResult method is a class member function that reads the file to get the final result. To keep the C++ code somewhat simple, we used redirection of streams into a file, whereas normally, using named pipes is the better solution. The path of the file is generated within the class constructor and placed into the mTempFileName variable, which is declared in the header file ( .h ) for the class. Additionally, when you create the .NET application that uses this object, you will see a brief window flash as the cmd.exe process is launched. To combat this flash, you normally want to create the cmd.exe process manually and hide the window using a parameter within the Win32 API function CreateProcess . Doing all of these steps, however, would result in a lot more code, which would complicate things more than they should.

You can now create the COM object and call its Run method. The next step is to add a property. Right-click on the interface again within Class View and select the Add Property menu item. The return type is a BSTR , and the name of the property is CurrentDirectory . The property will supports both a get and set operation, so leave those check boxes checked. The implementation of the methods for the properties are defined as follows :

 
 STDMETHODIMP CCommandCom::get_CurrentDirectory(BSTR* pVal) {     USES_CONVERSION;     TCHAR szBuffer[ MAX_PATH ];     GetCurrentDirectory( MAX_PATH, szBuffer );     *(pVal) = SysAllocString( T2OLE(szBuffer) );     return S_OK; } STDMETHODIMP CCommandCom::put_CurrentDirectory(BSTR newVal) {     return E_NOTIMPL; } 

Now that a method and a property are created, the last step is to give the object the ability to fire an event. Because we can't think of any possible events a command interpreter would fire, the event is used solely for testing. When you created the COM object, you checked the Connection Points check box. It created an additional interface that your class implements. Assuming you named your object ComClass , right-click on the interface named ICommandComEvents within Class View and add a new method that does not use any parameters. Finally, create a new method on the ICommandCom interface that also does not accept any parameters, and within its definition, fire the event that you created earlier using the raise keyword, as shown in the following code:

 
 STDMETHODIMP CCommandCom::Test() {     __raise SomeEvent();     return S_OK; } 

Comments

This recipe serves two purposes. The first is to serve as a reference point for further recipes within this chapter. The second is to familiarize you with COM concepts and ATL so that you understand what we're talking about and to compel you to investigate ATL, a very powerful library.

COM is an interface-based specification that lays a foundation for creating objects with rules governing their activation, use, and lifetime. When objects communicate with each other, they do so on specific interfaces that each one defines. Although .NET objects can also do this, disparate .NET objects have access to public methods and properties that aren't specifically declared as members of a specific interface, instead allowing method and property invocation on a class instance rather than through an interface.

The ATL is a template-based class library that facilitates the creation and use of COM objects. Due to its extensive use of templates and attributes, ATL shields C++ developers from internal COM plumbing code, allowing them to concentrate more on the implementation of their particular component. You can use ATL in a variety of different situations, including Internet Server API (ISAPI) extensions; Object Linking and Embedding Database (OLEDB) providers and consumers; Windows applications; Web services; and ATL Server, which is a tag-based server technology similar to ASP.NET.

 <  Day Day Up  >  


Microsoft Visual C# .Net 2003
Microsoft Visual C *. NET 2003 development skills Daquan
ISBN: 7508427505
EAN: 2147483647
Year: 2003
Pages: 440

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net