c++| Server
C + + is a standardized computer language that is not owned by anyone but belongs to a standard committee. STL is a C + + extension that supports data structures and algorithms. ATL is a template library owned and maintained by Microsoft, making COM programming easier. Synthesizing these technologies forms an effective way to create COM components for ASP pages.
Using all of these techniques to create a COM object, you'll see how the VC + + 6.0 Wizard provides a lot of code, so you can focus on solving problems rather than worrying about specific programming details.
17.3.1 problem
The most common way to represent data is the table, the column represents the type of field, each row is a record, and the value of the field. In a text file, a table is usually composed of a comma-separated value (comma-separated values,csv).
We will create a COM component that takes CSV data as input, efficiently stores it, and provides access functions to retrieve it. This data is represented in the COM component as an STL data structure. In later sections, we'll see how to use STL algorithms to process this data. In the next chapter, we will describe how to store this data in a database.
For illustration purposes, assume that the data is in a sparse table. The first row of fields is the column heading, followed by a record of data, each of which records the Zieux column headings. Comma isolation field, newline character (/N) Quarantine line, empty field with two commas, i.e. ",,".
Table 17-1 is an example of an expanded table. When you export, commas isolate each field.
17.3.2 Design
This component is designed to minimize data storage and access time. Because the data may be sparse, that is, many fields are empty, it is possible to minimize the storage space of the data. You can access the rows of data through a numeric value (a zero-based index), and you can access columns of data through field names. For example, to get the instrument of Keith Moon in table 17-1, you can call GetField (1, "instrument").
The tools for doing this are the vector and map data structures of the STL, which are containers, that is, they are objects that contain a collection of other objects. To access objects in the collection, use the STL traversal.
17.3.3 implementation
Now that you have a concept of the functionality of this component, we will implement it in the following steps:
? Create the DLL that contains the component.
? Create the component.
? Add properties.
? Increase the method.
1. Creating a DLL and a component
Select Atlcomappwizard, create a new VC + + project, and name it aspcomponents. Use the default server type (DLL) without selecting the check box, as shown in Figure 17-1.
When finished, the wizard will automatically generate a shell of the component. There are no components, and only the DLLs that are required by the COM specification exist, you can see them in the ASPCOMponents.cpp file, but don't care about the details of the file or change it. When you add a component to a DLL, the wizard modifies the file.
Now put the component into the DLL. Select the ClassView tab in the Workspace window, right-click aspcomponents Classes, and select New ATL Object. Then select Simple Object and type tablestorage in the short name box, as shown in Figure 17-2.
Unless you plan to study ATL more deeply, leave the default state on the Attributes tab without changing any options. A detailed description of the meaning of all these options is beyond the scope of this book. The Attributes tab is shown in Figure 17-3.
When you click OK, you have an object to work with.
So far, the VC + + Wizard has done all the work, and if you look at TableStorage.h, you will see the ATL code generated by the wizard. In most cases, you don't have to change the code. In fact, you can just rely on this code and continue programming without knowing ATL. However, the default settings need to be changed to make the generated code compile.
To reduce the size of a component, when AppWizard creates a component, it automatically turns off exception handling for C + +. Because if this feature is enabled, a C run-time library is required. The STL uses exception handling, so you need to enable it. In the Projectsettings dialog box, in the C + + tab, in the Drop-down category box, select C + + Language, make sure the Settings for box is set to all configurations, select Enable exception Handing check box, as shown in Figure 1 7-4.
If you compile in release mode, you may get a link error. This problem occurs when you compile a release version of an ATL project, and if exception handling is not closed. The C Run-time startup code is required when using exception handling, but in the default mode, the ATL project for release mode defines the _ ATL _MIN_CRT symbol, which rejects the startup code. To resolve this problem, delete _ atl_min_crt in the C/C + + preprocessor definition. For more information, see the article Q165259 in Microsoft's basic knowledge base.
Our added first code is used to create STL data structures, adding the following code to the beginning of TableStorage.h:
Here, two mappings and one vector are declared. This vector is actually one of two mappings. Using the TypeDef commands of C + + to define mappings and vectors is primarily to make code more readable and to describe data types better.
Column_index_map maps a string (the name of the column) to an index. Index_field_map represents the data for each row in the datasheet. Since he may be a sparse row, using a mapping implementation is efficient, and empty fields do not occupy any space. The Index_field_map map Column_index_map the provided index to the field value. Finally, Row_vector contains each mapping that represents the row.
The internal data structures are now described and can be used to use the properties of the external world.
2. Add attributes
We will add two attributes: The row Count property and the column number property.
Select the ClassView tab in the Project workspace and right-click the Itablestorage interface. Select Add property in the menu and fill out the dialog box as shown in Figure 1 7-5. Select the Get function check box without selecting the Put function check box to make it read-only.
Produces a get_numrows method that returns this property. This means that there is logic to produce the attribute value. In this case, you can set the property by calling the size () method of the row vector:
Now you have a way to get the number of rows and columns of stored data, and you need to have some data entered into your component, which is the next step.
3. Additional methods
So far, no data can be entered into the internal data structures or read from them. Add four methods below to complete the following tasks:
? Inserts data into the structure.
? Gets a field from the data structure.
? Gets the column name.
? Sorts the columns.
(1) Analysis of data
The first method gets a comma-delimited string, analyzes it, and then enters the data into the data structure.
Select the ClassView tab in the Project workspace and right-click the Itablestorage interface. Select Addmethod in the menu and fill in the dialog box as shown in Figure 17-6.
Then fill in the main part of the Parsecsv method with the following code:
The CSV data is passed as a string parameter, and two STL member variables are cleared, deleting the data entered when the method was previously called.
Pay special attention to the first row, because it contains the name of the column, and the name of each column is stored in M_columnindexmap as a key, indexed by the current size of the map. After a row is processed, you can take advantage of the fact that the index of the column name maps is the numeric index of the column. If the parsed field has data, it is stored in the Index_field_map.
Once all the rows have been processed, the storage space for the CSV data in the COM component has been minimized, and the access speed is accelerated by using mappings. Because only fields with actual values are stored, the storage space is minimal. Because maps are organized internally to organize data, they can be quickly retrieved and accessed quickly.
(2) Data access
Now that the data is stored efficiently, the next step is to be able to access it.
Add a new method called GetField to the Itablestorage interface and fill in the dialog box as shown in Figure 17-7.
Given the number of rows and column names, this method returns the value of the field, if it exists. Change the body of this method as follows:
The mapping method used to obtain the value corresponding to the mapped key is find. For Column_index_map mappings, return pair<wstring from Find, unsigned short> type of traversal. If no key is found, the traversal appliance has a value of m_columnindexmap.end (). If the key is found, the second member of the returned iterator contains the corresponding value: In this case, it is the index of the column name. This index is the key to the INDEX_FIELD_MAP mapping, and the field value is given by the row. If this value is found, it is returned through the [out, retval] argument, which is fieldvalue.
Below, create a method that gets the column name. Add a new method called getColumnName in Itablestorage and fill in the dialog box as shown in Figure 17-8.
Given the index of a column, this method returns the name of the column, changing the body of the method with the following code:
In this method, a linear lookup must be done through the mapping, because the program actually retrieves the value of the key instead of the key, traversing the m_columnindexmap mapping until it finds the index or searches the end of the map (that is, the index is not found). Note that the second member of the loop is used for comparisons, because the value of the key is found instead of the key. If the column index is found, the column name (actually the key) is returned through the [out, retval] argument, which is columnname.
(3) Sorting data
Add a method that has a real impact on the data below. Use the STL sort algorithm to sort the rows.
Then add a new method to the I Ta b l e s t o r a G e, and fill in the dialog box as shown in Figure 1 7-9:
Because the CTABLESTORAGE data structure is a combination of STL data structures (a mapping vector), a custom comparison function needs to be provided for sorting. For example, Ctablestorage::sort allows rows to be sorted by any column, which can use only one comparison function, or a function object. The column used for sorting is passed to the constructor of the function object Docompare.
Add the following function objects somewhere in the TableStorage.cpp file, such as between the implementation sections of the includes and Tablestorage classes.
This is the Declaration and implementation section of the Docompare function object, which is used in the sort comparison. Indeed, the function may look a little more complicated, and a detailed syntax explanation can be found in the C + + manual, but its purpose is very simple. Compares the rows to sort in the order specified by the m_direction parameter. The column number is used as the first parameter in the constructor and stored in a member variable (m_column). So, as a comparison, the function object knows which column to compare.
Note that the docompare is derived from the STL binary_function template. STL provides binary_function makes it very convenient to create comparison functions.
17.3.4 Test
This component can be used in many places: VB programs, ASP files, and even C + + programs. The following is an analysis of how to use in ASP.
First create a string csvstring, which represents the data. Creates a Tablestorage object with Server.CreateObject and analyzes the string using the Parsecsv method. This is where the data is in memory. Then sort by first name in ascending order.
Note that the entire code for the Componenttest.asp page can be downloaded from the Worx Web site, and the Visual C + + Project Aspcomponents in this chapter and in the next chapter is part of the source code for this book.
In addition, to get the value of a field, you must specify a field name. A more flexible interface should allow indexes to be used to get the value of a field. Running this page, the browser should get the display shown in Figure 1 7-1 0.
17.3.5 Error Handling
The two main aspects of error handling are:
? Make sure you can catch all the errors.
? Provides an accurate description of the error condition.
Using appropriate error-handling tools as early as possible during program development can significantly reduce development and test time, because errors can be detected and corrected more quickly. You can use exception handling in C + + to catch errors and use the Error object to feedback information to the client.
1. Exception Handling
Error handling capabilities are limited by program language. A typical error-handling process consists of the following:
? Call a function.
? Check the return value.
? If successful, the program takes a code path if the failure takes another.
The problem with this process is that it causes code nesting and is difficult to track. In addition, there is no way to force programmers to detect return values. They may be too lazy to check the return value or forget it.
We prefer the programming environment to catch errors for us and to boot the code to run on a predetermined error-handling route. You can do this with the On Error Goto < error handling function > in Visual Basic. When the error is generated, the program jumps to the specified error-handling function. You can also call Err.Raise in Visual Basic to mark an error.
C + + and Java have the same concept of error handling, called exception handling. Exception handling allows you to put part of the code in a try block to protect it. If the error results in a try block, then the execution of the program jumps to the catch block, where there is error handling code. When an error arises from a catch block, the code automatically points to the try block. Use the Throw keyword to emit an error message.
Here is a simple example of exception handling:
This exception handling style will be used in chapter 1th 8.
Once the error is caught, the next step is to return the error message to the user. If you are using a COM object hosting environment that is ASP, the best approach is to report an error through the Error object.
2. Error Object
If you do not use On Error Resume Next, when you call the GetField method on a field that does not have a value, you experience the following error:
This tip is of little use, and when the error arises, the component can provide more information, which can be done through the Error object.
If you create a new ATL object and use the Error object, you can select the Support isupporterrorinfo check box in the ATL Object Wizard Properties dialog box to instruct the wizard to produce code that supports the Error object.
With this modification, our class will support the ISupportErrorInfo COM interface. However, you need to insert the following code in the source file TableStorage.cpp to implement the incremental approach.
Our class derives from C COM coclass and has an error method. That is, the C Tablestorage class can use all of the public methods and properties defined by C COM Co class. Now the C Tablestorage class supports the error interface, so you can use this method. The C Tablestorage class also provides all of the parameters of the error object, including fault codes, descriptions, and help information.
Now not only has the added error message been obtained, but the ProgID of the component has been obtained. When the component supports ISupportErrorInfo, the ProgID information is automatically inserted.
In addition, I strongly recommend that programmers use error support early in component development. This will help programmers debug components and be able to help component users with their development efforts. Of course, if you can't tell what went wrong from the error message, the next step is to debug the program.
17.3.6 debugging
You can directly debug a normal executable program in Visual C + +. You can set breakpoints and then run programs in debug mode. If you have a DLL, you need to do more: the C + + debugger must attach a process that supports debugging.
A DLL is not running in its own process, it is running in another process. Therefore, the debugger must be bundled with the application process space that can hold the DLL. If you test in Visual Basic, you need to bundle up Visual Basic, and if you are testing on ASP, you need to bundle the Web server process. Also, in Visual Basic, you can run VB6.EXE, open a project that uses a DLL, and set breakpoints as normal.
There is also a way to set up a component for debugging directly, as long as the following line is added to the component where it needs to be debugged:
DebugBreak ();
When the process that holds the DLL program runs to this line, it stops to pop up a dialog box and tells you that you have come to a breakpoint and asks if you want to debug the application. Press Cancel to invoke the debugger (note that pressing OK does not enter the debugger). If you debug a component instead of a release, Visual C + + will start to run and stop where you inserted DebugBreak () when you press Cancel. This allows you to set additional breakpoints, observe variables, and do other debugging work.
The main problem with this approach is its intrusive nature. In order to debug your code you must modify the code, and be careful to avoid the legacy DebugBreak (). If there is a debugbreak () in the component product, the runtime pops up a dialog box and locks each user out of the Web server, waiting for the user to press OK or cancel. It's bad.
If the component is used in ASP, the following error occurs when you modify and then recompile:
Link:fatal error Link1168:connot Debug/aspcomponent.dll for writing
Error executing link.exe
The server component runs in the process space of the Web server, and if this error is obtained, it means that the server still has a reference to this component. Rather, the server is referencing the DLL in the component, so a reference to the DLL needs to be lifted. However, doing so requires shutting down and restarting the WWW service. However, if the object is running in MTS, the process is much simpler.
COM + debugging
First, determine that the set Activation attribute (activation property) is a dedicated server process rather than a library process. This ensures that the debugger is bound to the process of the component you are debugging. On the Project Settings tab, set the executable fordebug session entry to Dllhost.exe and set the program arguments key to ProcessID: < process ID. As shown in Figure 1 7-11.
The process I d can be obtained by right-clicking the application icon in Component Services Explorer and selecting Properties, as shown in Figure 1 7-1 2.
Close the server process for the application where the component resides, ensuring that the component does not currently reside in memory. Otherwise, you might use a component instance that does not have a binding debugger. The debug version of the component is established, the desired breakpoint is set in the debug build, and the program is executed from the Build menu.
Runs a Dllhost.exe with program parameters to indicate that it loads the application that contains the component being debugged. Because the COM + process binds the debugger, the debugger can break the call at the breakpoint whenever the component is accessed.
If the object fails, other cases about components in C + + are automatically placed in the event log.
This chapter describes the origins of C + + and sets the environment associated with developing ASP components. Readers have learned a part of C + +, such as STL and ATL, which are useful tools for creating ASP components. These tools are designed to meet the design needs of server components to reduce storage space and access time. To describe how they are used, this chapter creates a generic component that can be used with any application.
An important aspect of the capabilities of a component is its error handling. C + + exception handling provides an efficient way to catch errors in an assembly. To report an error outside of the application invocation, the component needs to support ISupportErrorInfo.