![]() |
![]() |
All Products | Support | Search | microsoft.com Guide | |||||||||||||||
![]() | |||||||||||||||||
| |||||||||||||||||
| May 7, 1996 | Back to Microsoft Access Archives | |
Upsizing Microsoft Access-Based ApplicationsJim SturmsMicrosoft Corporation
Contents
IntroductionThe purpose of this paper is to enable the developer of Microsoft® Access-based applications to use and understand fully the Microsoft Access Upsizing Tools. The developer should be able to use the tools to facilitate client/server development between Microsoft Access and Microsoft SQL Server™. The paper will discuss design strategies for using the tool optimally in the development process. What You Will Learn
OverviewThis paper has three sections:
The Upsizing Tools and the sample application used in this document will be available on the Tech*Ed CD. The application is for your personal use: You may learn from it and reuse code segments. However, they cannot be redistributed for production use. The reader is assumed to be familiar with the design of Microsoft Access-based applications and conversant with Microsoft Access Basic programming techniques. No prior experience with using SQL database data sources is assumed for this paper. This paper focuses on the use of the Microsoft Access Upsizing Tools. The tools, which were released in April 1996, are a free add-on for Microsoft Access 95. The tools are designed to work with Microsoft SQL Server database management system versions 4.21, 6.0, and 6.5. You need both Microsoft Access 95 and Microsoft SQL Server to use the Upsizing Tools. The Upsizing Tools consist of two major components:
Below is a description of these two major components, which we will be discussing throughout the paper. Upsizing WizardThe first component of the Upsizing Tools is the Upsizing Wizard. It takes a Microsoft Access database and creates an equivalent database on SQL Server with the same table structure, data, and many other attributes of the original Microsoft Access database. This will allow developers who design client/server applications on their desktop in Microsoft Access to generate a SQL Server database from their prototype. Also, developers who have existing Microsoft Access-based applications will be able to "grow" those applications to SQL Server and gain the benefits of a client/server architecture. SQL Server BrowserThe SQL Server Browser allows developers to view, create, and edit SQL Server objects, including tables, views, defaults, rules, stored procedures, and triggers. The Browser can be used to manage a SQL Server database created by the Upsizing Wizard or any other existing SQL Server objects. Before UpsizingThe first question we need to discuss is, "Why do we want to upsize a file server database to client/server?" The main reasons to do this are the benefits that a client/server configuration can offer, including improved performance, security, and reliability. Database application solutions inherently grow and become more complex over time. Developers need the assurance that they have a path to scale as their applications become larger and more complex and must support more users. In addition to scaling an existing application, the process of upsizing is also useful for jump-starting client/server development. By this, I mean that Microsoft Access is a very powerful file server database management system that, in addition to allowing a developer to build solid solutions, also offers the ability to rapidly prototype client/server solutions for prospective clients. Microsoft Access' rapid application development tools allow for many iterations of a prototype without the inherent complexities of client/server. It also allows for testing the initial designs without deploying the final, more robust back end. Once the plan is final, the upsizing process allows the developer to use the initial prototyping work to quickly build the data structure and rules on the server to jump-start the server-based work. Before we can upsize an application to SQL Server, there are several important design issues we need to take into consideration. Ideally, we would design an application with client/server deployment in mind from the very beginning. As we will see, the design to build an optimized client/server application is often very different than a file server-only application. If you have an existing application that was not built with client/server in mind, you will likely need to retrofit your application in order to take advantage of the upsizing process to follow. Design Tips -- Client Side
Create ODBC Data SourceYou need to make sure you have the ODBC data source you will need for upsizing. You should also decide which database you plan to upsize and make a backup copy of it. The Upsizing Wizard requires that you log on to a SQL Server database. If you are creating a new SQL Server database, you should make sure you have an ODBC data source for the Master database for the SQL Server you want to upsize to. If you are upsizing to an existing database, the Pubs sample database, for example, make sure you have an ODBC data source for Pubs. You can create an ODBC data source by running the ODBC Administrator. When using Windows® 95 or Windows NT® 4.0, you create an ODBC data source using the 32-bit ODBC icon in the Control Panel. Important: If you click Options and then select the Convert OEM to ANSI Characters check box when you create your data source, you must click Select and then specify a code page translator. If you select the Convert OEM to ANSI Characters check box and don't select a code page translator, the Upsizing Wizard will fail. Design Tips -- Server Side
Estimate SQL Server Database and Device SizeIf you are creating a new database, the Upsizing Wizard will ask you to select devices for your database and, optionally, a log. It will also ask you to set the size of the database itself. To answer these questions, you should estimate how much space your new database will require. Database Size When SQL Server creates a database, it sets aside a fixed amount of space for that database on one or more devices. Not all this space is necessarily used by the database. Database size is just the upper limit on how large a database can grow before it runs out of space. By looking at the size of your Microsoft Access database and estimating the rate at which your new SQL Server database will grow, you can arrive at a rough estimate of the space needed for your database. If you have ample disk space on your server, simply multiply the size of your Microsoft Access database by two. This will ensure that the Upsizing Wizard has enough space to upsize your database and leave it some room to grow as well. If you expect a lot of data to be added to the database, you should make the multiple larger. The Upsizing Wizard works best when there is plenty of disk space available. In situations where disk space is scarce, it is possible to fit an Microsoft Access database onto a SQL Server database less than twice its size. In general, every megabyte of Microsoft Access data will require 1.3 to 1.5 megabytes on SQL Server. Remember that the size of a Microsoft Access .mdb file includes all Microsoft Access objects, not just data. Device Size All SQL Server databases and logs are placed on devices. At one level, a device is merely a logical location to put databases and logs. At a lower level, a device is a physical file. When a device is created, SQL Server creates a file, thus reserving a set amount of disk space for its own use. A device can be thought of as a fixed portion of disk space that SQL Server sets aside for its own use. If no devices have enough free space, you may create a new device using the Upsizing Wizard. New devices should be at least as big as your estimated database size. It is recommended that you make the device still larger if possible. This will let you expand your new database later or place other databases or logs on the same device. In SQL Server 4.21, the size of a device cannot be changed. Make sure you create devices that are sufficiently large. SQL Server 6.x allows you to increase the size of your devices, but not decrease them. Once you've arrived at an estimate of how much space your new database will require, you will know how big a device you must have. The Upsizing Wizard will show how much free space is available on each available SQL Server device and allow you to choose which one you want. DevicesIn most cases, the Upsizing Wizard provides more than enough control over SQL Server devices. There are two cases where you may wish to create devices before running the Upsizing Wizard. Servers With More Than One Physical Disk If your server has more than one physical hard disk, you may want to place your database on one disk and the log for the database on a different disk. In the event of a disk failure, the likelihood of recovering will be much greater. The Upsizing Wizard allows you to create new devices but only on one physical disk -- the same disk as the Master database device. To place a database and log on separate disks, make sure you have devices that are big enough on both disks, creating new devices if necessary, and then run the Upsizing Wizard. Placing New Databases or Logs on Multiple Devices SQL Server allows databases and logs to span several devices. However, the Upsizing Wizard allows you to place databases and logs only on a single device or the "Default" device. If you want to specify multiple devices for a database or log, make those devices default devices. Make sure only those devices are set as default. Then run the Upsizing Wizard and choose "Default" for the database or log device. Note that if the size you specify in the Upsizing Wizard for the new SQL Server database or the size of the log doesn't require using all the devices set as default, SQL Server will use only the devices necessary to accommodate the database or log. The Upsizing ProcessThe Upsizing Wizard allows you to create a new SQL Server database. Or, if you have previously upsized your Microsoft Access database or you want to add Microsoft Access tables to an existing SQL Server database, you can upsize to an existing database. |
|
Exporting Table Properties and Linking Server TablesThe Upsizing Wizard can export additional table properties and create timestamp columns in the SQL Server table. The wizard can also modify your Microsoft Access database so that your queries, forms, and reports use the data in your new SQL Server tables, rather than the data in the local Microsoft Access database. |
|
Timestamp ColumnsBy default, the Upsizing Wizard creates new columns with the data type of timestamp in SQL Server tables generated from Microsoft Access tables that contain floating-point (single or double), Memo, or OLE fields. A timestamp field contains a unique value, generated by SQL Server, which is updated whenever the record is updated. Microsoft Access uses the value in timestamp fields to see if a record has been changed before updating it. A timestamp field provides the best performance and reliability. In the absence of a timestamp field, the Microsoft Jet database engine must check all the fields in the record to determine if the record has changed, which slows performance. Microsoft Access does not check to determine if text or image fields have changed because these fields could be many megabytes in size and the comparison could be too network intensive and time consuming. Therefore, if only a text or image field has changed and there is no timestamp field, the Microsoft Jet database engine will overwrite the change. Also, the value of a floating-point field may appear to have changed when it hasn't, so Microsoft Access may determine that the record has been changed when it has not. You can also choose to have the Upsizing Wizard create a timestamp field for all upsized tables, regardless of what field types they contain. In particular, this improves the performance of tables that don't contain Memo, OLE Object, or floating-point fields, but have many fields of other types. A timestamp field prevents Microsoft Jet from having to check all of the fields to determine if a record has been changed. Linking Server TablesThe Upsizing Wizard can modify your Microsoft Access database so that your queries, forms, and reports use the data in the new SQL Server database rather than the data in your Microsoft Access database. The wizard renames the Microsoft Access tables you export with the suffix "_local." For example, if you export a table named Employees, the table is renamed Employees_local in your database. Then, the wizard creates a linked SQL Server table named Employees. Forms, reports, and queries based on the original Employees tables will now use the SQL Server Employees table. Field Names and Aliasing QueriesSQL Server will not allow spaces or symbols in field names other than #, $, and _. The Upsizing Wizard automatically replaces spaces and illegal characters with the "_" symbol. If field names were changed when a table was exported, the wizard names the linked table with the suffix "_remote." The Upsizing Wizard then creates an aliasing query so that forms, reports, and queries will work properly on the new server table. For example, if you export a table Employees, the wizard creates a linked table called Employees_remote and renames the Employees table to Employees_local. The wizard then creates an aliasing query called Employees to accommodate the fact that the field names on the SQL Server are different. |
|
|
Note: There is no performance penalty for using aliasing queries instead of linked tables. FinishingWhen you reach the final screen in the Upsizing Wizard, it offers to create an upsizing report. The upsizing report documents what objects the Upsizing Wizard created on SQL Server. It includes information about any devices and databases that were created as well as a complete explanation of how each Microsoft Access object that was upsized maps to a SQL Server object. After upsizing is complete, you can view this report on screen or print it for future reference. The upsizing report cannot be saved to disk. To save this information, you must print the report. How the Upsizing Wizard WorksThe Upsizing Wizard makes upsizing a Microsoft Access database to SQL Server practically transparent. This section refers to specific SQL Server objects that are created when the database Employee.mdb is upsized. This sample database is included on the Tech*Ed CD. You may find the examples easier to understand if you upsize this database and then use the SQL Server Browser to access the objects discussed in the examples. Overview of Object MappingTo upsize a Microsoft Access database to SQL Server, the Upsizing Wizard creates SQL Server objects that, as far as possible, do everything the Microsoft Access database did. In some cases, mapping Microsoft Access objects to SQL Server objects is very straightforward. Microsoft Access databases, tables, fields, defaults, and indexes map to SQL Server databases, tables, fields, defaults, and indexes. This is a direct, one-to-one mapping. However, this is not the case for all objects. Validation rules and referential integrity, in Microsoft Access, are part of the data dictionary and are enforced at the engine level. In SQL Server, validation rules and referential integrity can also be implemented as code bound to a table (triggers). These differences, as well as design decisions made by the Upsizing Wizard, mean that much of the Microsoft Access data dictionary cannot be mapped directly to SQL Server constructs. The following table summarizes how objects are mapped from Microsoft Access objects to SQL Server.
The following sections discuss each Microsoft Access object and the SQL Server object (or objects) to which it maps. Database and Table ObjectsA Microsoft Access .mdb file maps directly to a SQL Server database. A Microsoft Access table, excluding much of its data dictionary, maps to a SQL Server table. The Upsizing Wizard replaces illegal characters with the "_" symbol. Any names that are SQL Server keywords, FROM or GROUP, for example, have the "_" symbol appended to them, resulting in the names FROM_ and GROUP_. Links to New Server TablesIf you selected the Attach newly created SQL Server tables check box, the Upsizing Wizard will create the linked tables as well as give them many of the properties of the fields in the original local table. Fields in linked tables inherit the following properties from the original fields:
Note: Linked tables were referred to as attached tables in Microsoft Access 2.0. IndexesSQL Server and Microsoft Access indexes are very similar. Microsoft Access primary keys are converted to SQL Server non-clustered, unique indexes. The primary key index is always named with a prefix of "aaaaa." In SQL Server 6.x, this index is also marked as a SQL Server primary key. When linking to a remote table, Microsoft Access chooses the index that is first alphabetically in the list of available indexes as the primary key. The "aaaaa" prefix ensures that the right index is chosen. All other indexes retain their names, except where they contain illegal characters. Illegal characters are replaced with the "_" symbol. Unique and non-unique Microsoft Access indexes become unique and non-unique SQL Server indexes. SQL Server doesn't support ascending or descending indexes. Example The following table lists the indexes created when an Employees table is upsized.
FieldsField names and data types are automatically translated into SQL Server fields when a Microsoft Access table is exported by the Upsizing Wizard. Microsoft Access data types map to SQL Server data types as follows:
DefaultsA Microsoft Access default expression maps directly to a single SQL Server default. While largely similar, there are some differences in the way defaults are created and behave in the two products. SQL Server defaults are independent of any particular field or table. Once a default has been created, it can be used or "bound" to any number of different fields. The Upsizing Wizard tries to create a SQL Server default based on the default expression for a Microsoft Access field. Defaults created by the Upsizing Wizard are named according to the SQL Server table to which they are bound, with a number that represents the position of the field in the Microsoft Access table definition. (This is the same as the order in which the fields appear in Table Design view.) If two or more fields have the same nonzero default expression, the Upsizing Wizard creates two defaults that are functionally identical with different names. Fields with a default expression of zero are bound to a default named UW_ZeroDefault. If any exported tables contain AutoNumber fields, the UW_ZeroDefault is automatically created and bound to each of those fields, whether or not you chose to export defaults. Also, any Yes/No fields that don't have a default will automatically have a "no" default bound to them. This makes interaction between Microsoft Access and SQL Server much smoother. The upsizing report will indicate whether the Upsizing Wizard was successful in translating the Microsoft Access Basic expression to SQL Server Transact-SQL. If the default was successfully created, the wizard binds it to the appropriate SQL Server field. TriggersA trigger is a series of Transact-SQL statements associated with a particular SQL Server table. The Upsizing Wizard uses triggers differently depending on whether you are upsizing to SQL Server 4.21 or 6.x and whether you choose to use declarative referential integrity on SQL Server 6.x. SQL Server 4.21 AutoNumber fields, validation rules, and table relations map to SQL Server triggers. The Upsizing Wizard creates triggers when you export validation rules or table relationships, or when your table contains an AutoNumber field. SQL Server 6.x If you choose to use triggers to implement referential integrity, table relations will map to SQL Server triggers. Validation rules always map to SQL Server triggers. Validation rules and table relations do not map directly to triggers. Each rule or relation may become part of several triggers. Each trigger may contain code to emulate the functionality of several validation and referential integrity rules. A table can have three triggers, one for each of the commands that can modify data in the table: the Update, Insert, and Delete commands. The trigger is automatically executed when the command is carried out. The following table describes the triggers created by the Upsizing Wizard. Any specific trigger may contain code to emulate one, all, or none of the Microsoft Access functions listed.
Declarative Referential IntegrityDeclarative referential integrity (DRI) is new functionality introduced in SQL Server 6.0. DRI allows you to declare relationships between tables with the table definition. For example, the Dept ID field in the Employees table is a foreign key to the Dept ID field in the Departments table. SQL Server DRI allows you to create these foreign keys as part of the table definition. DRI on SQL Server does not support the cascading updates and deletes that are allowed in Microsoft Access. When upsizing to SQL Server 6.x, the Upsizing Wizard gives you the option of using DRI or triggers to enforce referential integrity. If your Microsoft Access database contains cascading updates and deletes, the Upsizing Tools will default to using triggers to maintain the cascades. You have the option of using DRI instead, but your cascades will not be upsized. AutoNumber FieldsAutoNumber fields in Microsoft Access are Long Integer fields that are automatically incremented. SQL Server 4.21 doesn't support the AutoNumber data type, so the Upsizing Wizard includes code in the Insert triggers that provides equivalent functionality. In SQL Server 6.0, AutoNumber fields are upsized to SQL Server Identity columns. Identity columns are functionally equivalent to AutoNumbers. Note: On all supported versions of SQL Server, the functionality of random AutoNumber fields that use the Long Integer field size are reproduced by using triggers. The functionality of random AutoNumber fields that use the ReplicationID (GUID) field size cannot be reproduced. Example The Transact-SQL code below was generated as part of upsizing a Tasks table and is contained in the trigger called Tasks_ITrigger. This code provides the same functionality as the AutoNumber field Task ID in a Microsoft Access table Tasks. |
|
Validation RulesThe Upsizing Wizard can export table validation rules and field validation. For each table, the Upsizing Wizard:
Note: The Upsizing Wizard uses triggers rather than SQL Server rules to enforce field level validation because SQL Server rules do not allow you to display custom error messages. Example The following code is contained in both the Tasks_Itrig and Tasks_Utrig triggers, which are associated with the Tasks table. This code is the SQL Server equivalent of two Microsoft Access field level validation rules (for the Status and Date Completed fields) and one Microsoft Access table validation rule. |
|
|
Note: The user-defined error number of 44444 is used for all instances where validation rules (table validation, field validation, and the Required property) are violated. Required PropertyWhen the Required property of a Microsoft Access field is set to true, a user cannot insert a record and leave the required field null (if there is no default bound to the field) or make the field null when updating a record. The Required property is handled differently in SQL Server 4.21 and 6.x. In SQL Server 6.x, required fields are mapped to fields that do not allow Nulls on SQL Server. In SQL Server 4.21, the Upsizing Wizard generates SQL Server Transact code to emulate the Required property. Example The following code is generated because the Required property of the Emp ID field in the Tasks table is set to true. The code is contained in both the Tasks_Utrig and Tasks_Itrig triggers of the Tasks table. |
|
Table RelationshipsTable relationships are handled differently on SQL Server 4.21 and SQL Server 6.x. Important: If only one of the tables in a relationship is upsized or if referential integrity is not enforced in Microsoft Access, the relationship is not exported. SQL Server 4.21 The Upsizing Wizard creates triggers that include the Transact-SQL code required to duplicate Microsoft Access table relationships. Microsoft Access supports declarative referential integrity that is enforced at the engine level. In SQL Server 4.21, referential integrity is enforced by Transact-SQL code in triggers. A Microsoft Access relationship becomes four SQL Server triggers: two for the parent table and two for the child table. Parent Table The Upsizing Wizard will create an Update trigger that will either prevent changing the parent table's primary key or cascade that change through the child table, depending on the type of relationship that was created in Microsoft Access. The wizard will also create a Delete trigger that prevents deleting a record with related child records or that deletes the child records, again depending on the type of the original relationship between the tables in Microsoft Access. Examples The following Transact-SQL code is contained in the Departments_Dtrig trigger of the Departments table. It prevents deleting a parent record that would orphan related records in the Employees table. |
|
|
The second example illustrates how changes to the primary key (the Email field) are cascaded to the child table's foreign key. The code is contained in the Employees_Utrig trigger of the Employees table. |
|
|
Child Table For the child table, the Upsizing Wizard creates an Update trigger that prevents changes to the foreign key that would orphan the record. Likewise, an Insert trigger is created to prevent a new record from being added that has no parent. Example This code prevents adding a record to the Tasks table if no parent record exists in the Employees table and is contained in the Tasks_Itrig trigger. |
|
|
|
You may need to modify your code in light of this difference. If your nested transactions are rolled back when any of them fail, the single-transaction limitation won't pose major difficulties. If some nested transactions are committed even if others fail, duplicating this functionality with one transaction may prove to be difficult. Default and AutoNumber ValuesMicrosoft Access default and AutoNumber field values appear when you begin editing a new record. Default values generated by SQL Server defaults and AutoNumber values generated by table triggers appear only after a record has been inserted. You will need to change any code, such as code for lookups, that depends on having the values before the record is committed. Validation RulesIn Microsoft Access, field validation occurs when the user tabs out of a field. When you edit SQL Server data in linked tables, triggers and rules are not fired until you leave the record. Record validation rules that rely on field validation occurring when a field is exited may need to be modified. Unconverted ExpressionsThe upsizing report shows whether each Microsoft Access table validation rule, field validation rule, and default was successfully converted. If the Upsizing Wizard was not successful in translating a Microsoft Access Basic expression, you will need to rewrite it using Transact-SQL. For example, if a field validation rule could not be converted, you should rewrite the validation rule in Transact-SQL and then add it to the update and insert trigger for the table. You could also create a rule. Another option is to perform validation at the form level in Microsoft Access. However, if server data is then modified without using a particular form, the validation will not be applied and invalid data may be entered. Record LockingYou cannot open a Dynaset object against a linked server table in exclusive mode. Consequently, the value of the Record Locks property of all forms must be set to No Locks or Edited Record. (Edited Record is treated the same as No Locks.) The value All Records is illegal and generates an error. With server tables, Microsoft Access uses optimistic locking internally. The row is locked only while the update process occurs, when the edited value is committed, which is usually a very brief interval. Back-End DatabasesMany developers take a "back-end, front-end" approach to developing Microsoft Access applications. They keep tables in one database (the back end) and all other objects such as forms and reports in another database (the front end). To upsize a back-end/front-end application
SQL Server BrowserAs we discussed earlier in this document, the Upsizing Tools contain an additional tool -- the SQL Server Browser. It is essentially a client/server database container integrated into your Microsoft Access development environment. It allows you to view, edit, and modify SQL Server objects, including tables, views, rules, defaults, and stored procedures. This allows developers to leverage their understanding of the Microsoft Access developer toolset when developing against the back-end database. The SQL Server Browser can perform many of the same functions as the SQL Enterprise Manager, which is provided with Microsoft SQL Server 6.x. This section outlines the important differences between the SQL Server Browser and the SQL Enterprise Manager, to help you choose the tool that best suits the task. User InterfaceMicrosoft Access users will find the SQL Server Browser interface familiar and easy to use. The SQL Enterprise Manager is powerful and easy to use, but doesn't resemble the Microsoft Access interface. The SQL Server Browser allows you to view, edit, create, and delete objects, in windows similar to the Microsoft Access Database window and Table window in Design view. However, in the SQL Server Browser, you must use ad hoc SQL for the following tasks:
Modifying a SQL Server TableYou cannot delete any fields in the Table window because SQL Server doesn't allow you to drop columns from existing tables. Caution: Each modification to an existing table is made immediately, rather than when you close the Table window. To modify a table
Note: Data type, field length, the Required property setting, and validation rules cannot be modified in existing tables. Expression TranslationWhen adding defaults to SQL Server via the SQL Server Browser, you can use the most common Microsoft Access expression, and the SQL Server Browser will convert this expression to a SQL Server expression. The following expressions are converted:
As part of translating expressions, the Upsizing Wizard and SQL Server Browser replace a number of delimiters, operators, constants, and wildcard characters, as listed in the following table.
THESE MATERIALS ARE PROVIDED "AS-IS," FOR INFORMATIONAL PURPOSES ONLY. NEITHER MICROSOFT NOR ITS SUPPLIERS MAKES ANY WARRANTY, EXPRESS OR IMPLIED WITH RESPECT TO THE CONTENT OF THESE MATERIALS OR THE ACCURACY OF ANY INFORMATION CONTAINED HEREIN, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. BECAUSE SOME STATES/JURISDICTIONS DO NOT ALLOW EXCLUSIONS OF IMPLIED WARRANTIES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU. NEITHER MICROSOFT NOR ITS SUPPLIERS SHALL HAVE ANY LIABILITY FOR ANY DAMAGES WHATSOEVER INCLUDING CONSEQUENTIAL INCIDENTAL, DIRECT, INDIRECT, SPECIAL, AND LOSS PROFITS. BECAUSE SOME STATES/JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CONSEQUENTIAL OR INCIDENTAL DAMAGES THE ABOVE LIMITATION MAY NOT APPLY TO YOU. IN ANY EVENT, MICROSOFT'S AND ITS SUPPLIERS' ENTIRE LIABILITY IN ANY MANNER ARISING OUT OF THESE MATERIALS, WHETHER BY TORT, CONTRACT, OR OTHERWISE SHALL NOT EXCEED THE SUGGESTED RETAIL PRICE OF THESE MATERIALS. |
|
|
|
|
||
|
Comments? Suggestions? Write us at MSDN@microsoft.com. |
||
| © 2000 Microsoft
Corporation. All rights reserved. Terms of Use. Last Updated: January 4, 2000 |
||
| Best experienced with Click here to start. |
||