Providing User-Selectable Report Criteria in Your Programs

Editor's Note: This example project requires the Professional edition of Visual Basic.

Let's face it: There isn't enough time to write all the reports that users would like to see. No matter how many reports your new system generates, there's always one user who wants to see a different set of records. That leaves you heading back to your source code to write another boring report.

Fortunately, with the advent of Standard Query Language (SQL), there's a light at the end of the report-writing tunnel. You can write a basic report-generating program and let the user specify which records the report should include.

In this article, we'll show you how to provide user-selectable report criteria in your programs. Doing so is easier than you may think when you take advantage of the simple SQL Select statement.

Three copies on my desk in the morning

When users need flexible reporting or when you wish to create one report for several users with different needs, you should most likely create a program that allows users to specify exactly which report criteria they want. As it turns out, you'll probably be surprised at how easy it is to do so.

All you do is let the user build a SQL query string, then build a SnapShot object based on the SQL query. To let users build the SQL query, you provide a list box containing all the fields they can select, a set of option buttons for specifying an operator, and a text box for entering a SQL comparison value.

An example

We've included an example project that lets users specify report criteria and then fills a list box with the results of their selections. We based our example program on a database you already have—BIBLIO.MDB. Visual Basic includes BIBLIO.MDB as an example database and places the file (by default) in the VB directory.

Incidentally, once you have our example program up and running, you'll be able to modify it easily to work with your own databases or to send its results to the printer instead of the onscreen list box. We'll mention how to do so at the appropriate time.

To get started, load and run VB; then start a new project. There will be only one form in this project, but that form will contain many fields. Figure A shows the completed SELECT project's main form.

Figure A

The SELECT project's main form will contain many fields.

Table A contains a list of all the SELECT form's fields and the properties you should set for each of them. Add the fields to your form, being sure to add the Frame control first; then place in the frame all the controls except the lstResults list box. Notice that the Option Button controls are actually part of a control array called optOperator; when VB asks if you wish to create a control array, click Yes.

After you add all the controls to your form and set their properties according to Table A, you're ready to save your project. Select Save Project from the VB File menu, then enter frmSelct as the Form name and SELECT as the project name.

Table A: SELECT project controls and properties

Control | Property | Value
Frame | Caption | "Report Criteria"
List Box | Name | lstFields
Option Button | Name | optOperator
 | Caption | "Equal to"
 | Index | 0
Option Button | Name | optOperator
 | Caption | "Less than"
 | Index | 1
Option Button | Name | optOperator
 | Caption | "Greater Than"
 | Index | 2
Option Button | Name | optOperator
 | Caption | "Less than or equal to"
 | Index | 3
Option Button | Name | optOperator
 | Caption | "Greater than or equal to"
 | Index | 4
Text Box | Name | txtValue
 | Text | ""
Cmd Button | Name | cmdExit
 | Caption | "Exit"
Cmd Button | Name | cmdClear
 | Caption | "Clear"
Cmd Button | Name | cmdOK
 | Caption | "Go"
 | Enabled | False
Label | Name | lblQuery
 | Caption | ""
Label | Caption | "Field"
Label | Caption | "Operator"
Label | Caption | "Value"
List Box | Name | lstResults

Add some code

As you might imagine, you need to add some code to your project. First, you must declare a number of constants and form-level variables to the General Declarations section of your form. Add the code in Listing A to your General Declarations section.

Listing A: General Declarations code

Option Explicit

' define form-level database variables

' the BIBLIO.MDB database
Dim dBiblio As DATABASE

' Database location
' *********** NOTE ************
' YOU MUST SPECIFY THE CORRECT
' PATH FOR THE BIBLIO.MDB DATABASE
' WHERE IT EXISTS ON YOUR SYSTEM
Const sFileName = "C:\VB\BIBLIO.MDB"

' the Author table
Dim tbAuthors As Table

' the table name
Const sTableName = "Authors"

' the query string
Dim sQuery As String

Once you enter the General Declarations code, you can enter all the code for each of the control's events. Listing B contains all the controls' Event code; we've used alternate shading to show where each control's code begins and ends.

Listing B: Event code for all controls

Sub Form_Load ()

    ' set error handler for database
    On Error GoTo No_Open_DB

    ' open the database
    Set dBiblio = OpenDatabase(sFileName, True)

    ' set error handler for table
    On Error GoTo No_Open_Table

    ' open the table
    Set tbAuthors = dBiblio.OpenTable(sTableName)

    ' turn off error handler
    On Error GoTo 0

    ' fill the list box with field names
    GetFields

Normal_Exit:

    ' everything's open: Get out
    Exit Sub

No_Open_DB:

    ' could not open the database
    MsgBox "Could Not Open " + sFileName + ", " +
Þ       Error$(Err) + ", Err#=" + Str$(Err)

    ' get out
    End

No_Open_Table:

    ' Could not open table
    MsgBox "Could Not Open " + sTableName + ", " +
Þ      Error$(Err) + ", Err#=" + Str$(Err)

    ' Close database
    dBiblio.Close

    ' get out
    End

End Sub

Sub Form_Unload (Cancel As Integer)

    ' close the database and the table
    tbAuthors.Close
    dBiblio.Close

    ' get out
    End

End Sub

Sub lstFields_Click ()

    ' user selected field,
    ' rebuild query string

    BuildQueryString

End Sub

Sub optOperator_Click (Index As Integer)

    ' user selected operator
    ' build query string

    BuildQueryString

End Sub

Sub txtValue_Change ()

    'user entered value
    'build query string

    BuildQueryString

End Sub

Sub cmdOK_Click ()

    ' they're ready to create a report
    CreateReport

End Sub

Sub cmdExit_Click ()

    ' end the program
    Unload Me

End Sub

Sub cmdClear_Click ()

    ' update the controls

    ' select no field
    lstFields.ListIndex = -1

    ' select no operator
    Dim i As Integer
    For i = 0 To 4
        optOperator(i).Value = False
    Next i

    ' no value
    txtValue = ""

    ' update the label
    BuildQueryString

    ' get rid of old results
    lstResults.Clear

End Sub

Be careful to enter each section of code in the appropriate control's Event code window. You'll enter form Load and Unload events, Click events for the lstFields and optOperator controls, a Change event for the txtValue edit box, and Click events for each of the three Command Button controls.

Special routines

With your form created, the controls added, and each control's Event code in place, you're ready to add the three subroutines that make this project work. To add these subroutines, first enter the declaration for each function (which appears in the first line of Listings C, D, and E, respectively) in the General Declarations section of your form. When you do so, VB will add the subroutines to your project, and you can enter the specific code for each subroutine.

Displaying the available fields

The first routine we'll add, GetFields, will add the field names from our database to the lstFields List Box control. Doing so lets users specify the field by which they wish to select their report. Add the code from Listing C, GetFields, to your project, starting by adding the declaration to your form's General Declarations section.

Listing C: GetFields

Sub GetFields ()

    ' fill the fields list box with the
    ' table field names

    Dim i As Integer

    ' get all the names
    For i = 0 To dBiblio.TableDefs(sTableName).
Þ                        Fields.Count - 1

        ' add the field name
        lstFields.AddItem dBiblio.TableDefs(sTableName).
Þ                                Fields(i).Name

        ' keep track of field type (Integer, String)
        ' end of list is current item
        lstFields.ItemData(lstFields.ListCount - 1) =
Þ                 dBiblio.TableDefs(sTableName).
Þ                      Fields(i).Type

    Next i

End Sub

Notice that the GetFields function keeps track of each database field's data type in the ItemData property of each list box element. Later in the program, we'll need to know the data type of the field that the user selects to report.

Building the query string

As the user selects fields and operators and specifies field criteria values, the program will build the SQL query string and display the string for the user. When the user is ready to generate the report, the program will use the query string explicitly by invoking the SQL command.

The BuildQueryString subroutine reviews the current database field, operator, and text box control values and builds the SQL query string according to the user's selections. Each of the selection controls, in turn, calls the BuildQueryString subroutine when a user changes the selection.

Add the code from Listing D, BuildQueryString, to your project. Be sure to first add the declaration of the BuildQueryString to the General Declarations section of your project.

You may have noticed the following lines from Listing D:

' if field type is string (type 10)
' be sure to add beginning quotation marks
If lstFields.ItemData(lstFields.ListIndex) =
Þ10 Then

Listing D: BuildQueryString

Sub BuildQueryString ()

    ' user selected report criteria
    ' build the query string

    ' can we execute query?
    Dim iQueryOK As Integer
    iQueryOK = True

    ' initialize
    sQuery = ""

    ' be sure something's selected
    If lstFields.ListIndex <> -1 Then

        ' the field name...
        sQuery = "[" +
Þ                lstFields.List(lstFields.ListIndex)
Þ                          + "]"

        ' the operator
        If optOperator(0).Value = True Then
                sQuery = sQuery + " = "
        ElseIf optOperator(1).Value = True Then
                sQuery = sQuery + " < "
        ElseIf optOperator(2).Value = True Then
                sQuery = sQuery + " > "
        ElseIf optOperator(3).Value = True Then
                sQuery = sQuery + " <= "
        ElseIf optOperator(4).Value = True Then
                sQuery = sQuery + " >= "
        Else
            ' no operator, no query
            iQueryOK = False
        End If

        ' the value
        If Trim$(txtValue) > " " Then

            ' add a space
            sQuery = sQuery + " "

            ' if field type is string (type 10)
            ' be sure to add beginning quotation marks
            If lstFields.ItemData(lstFields.ListIndex) =
Þ                                           10 Then
                sQuery = sQuery + "'"
            End If

            ' insert value based on field type
            If lstFields.ItemData(lstFields.ListIndex) =
Þ                                           10 Then
                sQuery = sQuery + Trim$(txtValue)
            Else
                sQuery = sQuery + Str$(Val(txtValue))
            End If

            ' if field type is string (type 10)
            ' be sure to add ending quotation marks
            If lstFields.ItemData(lstFields.ListIndex) =
Þ                                   10 Then
                sQuery = sQuery + "'"
            End If

        Else
            ' no value, no query
            iQueryOK = False
        End If

    Else

        ' no field selected, no query
        iQueryOK = False

    End If

    ' update the query label
    lblQuery.Caption = sQuery

    ' update the go button
    cmdOK.Enabled = iQueryOK

End Sub

Since string-value SQL clauses must be enclosed in quotation marks, the program must be careful to enclose the user's report value in quotation marks for string type data fields. The GetFields function (shown in Listing C) kept each field's data type with each list box element's ItemData property. The BuildQueryString function can then simply check the type of the field the user is querying and add quotation marks as necessary.

Creating the report

Once the program can build the SQL query string, the program can quickly and easily generate the report using the query string. In fact, the program can merely create a SnapShot object based on the query string, then report the contents of the SnapShot object in the lstResults list box.

The CreateReport subroutine uses the query string to create a SnapShot object. Once the subroutine creates the SnapShot object, creating the report is as simple as reading the SnapShot records and adding them to the lstResults list box.

Add the code from Listing E, CreateReport, to your project now. Remember to first add the CreateReport declaration to the General Declarations section of your form, then add the code from Listing E to your new subroutine.

Listing E: CreateReport

Sub CreateReport ()

    ' they've specified report criteria
    ' build query string,
    ' fill the list box with
    ' results of the report

    ' empty the results list box
    lstResults.Clear

    ' define a SnapShot object
    ' to obtain the results
    Dim snapResults As SnapShot

    ' build the SQL query
    Dim sSQLQuery As String

    ' start with the command
    sSQLQuery = "Select * from " + sTableName
Þ               + " Where "

    ' add the criteria set from user selection
    sSQLQuery = sSQLQuery + sQuery

    ' execute the query
    Set snapResults = dBiblio.CreateSnapshot(sSQLQuery)

    ' each record string for the report
    Dim sResults As String

    ' number of fields for report
    Dim iFieldCount As Integer
    iFieldCount = snapResults.Fields.Count

    ' loop variable
    Dim i As Integer

    ' add all the snapshot records to the
    ' report (list box for the example)
    Do While Not snapResults.EOF

        ' init result string
        sResults = ""

        ' build result string
        For i = 0 To iFieldCount - 1

            ' add field value
            sResults = sResults +
Þ                      snapResults.Fields(i)

            ' space over for next field
            sResults = sResults + Chr$(9)

        Next i

        ' place the results in the list box
        lstResults.AddItem sResults

        ' move to the next record
        snapResults.MoveNext

    Loop

    ' Let 'em know there's no more records
    lstResults.AddItem "* * * End of " + sQuery
                      + " Query * * *"

    ' kill the snapshot
    snapResults.Close

End Sub

If you look closely at Listing E, you'll see the CreateReport subroutine needs only five lines to create the user's query from the database. These lines declare the SnapShot object and SQL statement, build the SQL statement from the Query string, then create the snapshot using the SQL statement and the CreateSnapShot method. That's it.

The remainder of the subroutine reads all the fields from the SnapShot object and adds them to the lstResults list box so users can see the results of their queries. If you in-tend to modify our example project to send results to the printer instead of the list box, simply replace the section of code commented "Place the results in the list box" with code that will send results to the printer.

Incidentally, the CreateReport function will always include all fields, in default order, in its results output. You may wish to update the results to include only the fields you wish to display. We'll address the details of modifying the report output in a future issue.

Testing the project

With everything in place, be sure to first save your project by clicking the Save File button or selecting Save Project from the VB File menu. When you've done so, run the project by clicking Run, selecting Start from the Run menu, or pressing [F5].

When the project runs, it will attempt to open the BIBLIO.MDB database and its associated Author table. If you get an error on program startup, be sure you've specified the proper path for the BIBLIO.MDB database in the General Declarations section of your form.

When the program loads correctly by opening the BIBLIO.MDB database and its Author table, it will present you with the form you created at the beginning of this article. Notice that the lstFields list box now contains two fields, which are the fields of the Author database.

Select the Author field to indicate that you wish to specify Author name criteria. Notice that the lblQuery label displays the partial SQL clause, which is based on the Author field you selected.

Next, select an operator, the Less Than option button. Notice that the lblQuery label now displays both the Author field and the less-than (<) operator.

Finally, specify a criteria value—the letter d. Notice that the program updates the lblQuery label with the entire SQL clause, which includes each of your three selections. Notice also that the program automatically encloses your letter 'd' in quotation marks, because the Author field is a String data type.

When you've entered the three selections, click the Go button, and the program will execute your query and fill the lstResults list box with the results. Figure B shows the form with our selection criteria, the SQL clause, and the results of the query.

Figure B

The SELECT project lets you specify your own unique report criteria, then generates the appropriate report for you.

Test the project with other fields, operators, and values. Notice that when you select the Au_ID field, the program doesn't enclose your report value in quotation marks, because that field is a numeric data type. Also, test the Clear button, which resets your criteria and clears the Results list box.

Finally, note that the program will continue to work for your databases, provided you name your database and table in the General Declarations section of the form. You don't have to change any other code to select any of the fields of your tables or to view all of your data.

Conclusion

Providing special reports for each of your users can be a programmer's nightmare. Providing one program that will generate a variety of reports is a little more work than creating one report, but far less than it would take to create a special report each time a user requires one.

This article is reproduced from the August 1995 issue of Inside Visual Basic for Windows. Copyright 1995, The Cobb Group. All rights are reserved. Inside Visual Basic for Windows is an independently produced publication of The Cobb Group. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of The Cobb Group. To contact The Cobb Group, please call (800) 223-8720 or (502) 493-3300.


Keeping Track of Database Record Placement by Using BookMarks

As you're most likely aware, by issuing an SQL command, you can make your program accomplish many database tasks. As you probably also know, your program must accomplish some of its tasks by reading record-for-record through your databases.

Reading all records in an Access database can be relatively simple. All your program needs to do is select an index, use the MoveFirst, FindFirst, or Seek method to locate a beginning record, then read the data from that record. To read all the records, your program uses the MoveNext or FindNext method to move forward in the database; it then checks the EOF property to determine when it has reached the end of the database.

Unfortunately, if during the loop that reads all of a database's records you need to look up a value in the same table, your program has a problem. Specifically, the record-scanning loop works only because it uses the MoveNext or FindNext method to move to the next record after the current record in the database. If your program upsets the current record by looking for other data, the loop most likely will not read accurately through all the records in your database.

Fortunately, Microsoft has added the BookMark property to Table, Dynaset, and Snapshot objects. By using the BookMark property, your program can note the current record position in your database and return to that position later.

In this article, we'll look at the BookMark property and show you how to use it to save the current record position. We'll also present an example program that uses the BookMark property to help look up data while scanning through a database, without losing the current record position.

What's the problem?

Let's take a look at some very simple Visual Basic code that reads through all the records in a database. Listing A contains VB sample record-scanning code.

Listing A: Record-scanning code

Sub Form_DblClick ()

' clear the form
form1.Cls

' open the database
Dim dbBiblio As Database
Set dbBiblio = OpenDatabase("C:\VB\BIBLIO.MDB", True, ÂFalse)

' open the table
Dim tbAuthor As Table
Set tbAuthor = dbBiblio.OpenTable("Authors")

' start at the top
tbAuthor.MoveFirst

' until end of file...
Do While Not tbAuthor.EOF

    ' print record information
    form1.Print tbAuthor!Author

    ' go to the next record
    tbAuthor.MoveNext

Loop

' close table
tbAuthor.Close

' close database
dbBiblio.Close

End Sub

As you can see, the code in Listing A opens the BIBLIO.MDB database (which comes with the VB sample code) and then opens its Author table. Once the code opens the database and the Author table, it reads through all the records in the database, displaying the current author's name. To move to the next record, the code uses the MoveNext method of the Author table. To determine when it has processed all the records, the code checks the Author table's EOF property. Finally, the code closes the Author table and then closes the BIBLIO.MDB database. Figure A shows the output from the program in Listing A.

Figure A This program loops through the data in a database.

Incidentally, if you want to check out this code for yourself, it should work as we've printed it, even on your machine. Just add the code from Listing A to a new project's Form1's _DblClick event. Once you've done so, double-click on the form, and the program will display the authors' names. Of course, you must have the Professional Edition of Visual Basic, and you'll need to specify the appropriate path for the BIBLIO.MDB database in the line that calls the OpenDatabase function.

As we've said, the code in Listing A will work properly, assuming of course that the BIBLIO.MDB table resides in the C:\VB directory (as we've specified in the OpenDatabase function call). However, the code won't work as well if the current record position changes before the code calls the MoveNext method. Let's take another look at the same code, but this time with the addition of one simple function call. Listing B contains our updated record-reading code, which no longer works as you'd expect.

Obviously, the code in Listing B will not display all the author names from the Authors table in the BIBLIO.MDB database. As you can see, the second statement in the Do loop moves to the last record in the database. Because the current record is then the last record in the database, when the program executes the MoveNext method, it reaches the end of the file and displays no more authors' names. Figure B shows the output from our errant program in Listing B, which displays only the author information from the first record in the database.

Listing B: Errant record-reading code

Sub Form_DblClick ()

' clear the form
form1.Cls

' open the database
Dim dbBiblio As Database
Set dbBiblio = OpenDatabase("C:\VB\BIBLIO.MDB", True, ÂFalse)

' open the table
Dim tbAuthor As Table
Set tbAuthor = dbBiblio.OpenTable("Authors")

' start at the top
tbAuthor.MoveFirst

' until end of file...
Do While Not tbAuthor.EOF

    ' print record information
    form1.Print tbAuthor!Author

    ' go somewhere else in the database
    ' to look up other information
    tbAuthor.MoveLast

    ' go to the next record
    tbAuthor.MoveNext

Loop

' close table
tbAuthor.Close

' close database
dbBiblio.Close

End Sub

Figure B The program no longer works because the current record positioning has been changed.

In more complex Do loop code sections, your programs may call functions that upset the current record. In those cases, your programs will also fail, and you may believe you're forced to recode small or even very large portions of your program.

The saving BookMark

Fortunately, the Table, Dynaset, and Snapshot objects supply the BookMark property. By using the BookMark property, you can let your programs change the current record positioning in any way they need to and then return to the current record for subsequent processing.

To use the BookMark property, you first declare a Variant (or non-fixed-length String) variable. To save the current record position, assign your Variant variable to the current value of the BookMark property of the Table, Dynaset, or Snapshot object you're reading through. For example, the lines

' the bookmark
Dim bmCurrentAuthor As Variant

' save where we are
bmCurrentAuthor = tbAuthor.BookMark

declare the bmCurrentAuthor variable of Variant data type and then store in it the current BookMark property value of the tbAuthor table.

To return to a particular record, simply assign the Table, Dynaset, or Snapshot's BookMark property to the value you saved earlier. For example, the lines

' return to the previous current record
tbAuthor.BookMark = bmCurrentAuthor

reset the current record position in the Author table to the one saved in the bmCurrentAuthor variable.

Remember, the BookMark property is not a record itself. The Table, Dynaset, and Snapshot objects use the BookMark property only to establish current record positioning. Don't attempt to use BookMark values with the MoveFirst or FindFirst methods—they won't work.

By using the BookMark property, we can repair our errant code in Listing B. In fact, all we need to do is save the current record position at the top of the Do loop, then restore the current position just before calling the MoveNext method to move to the next record. Listing C contains the corrected source code, which still moves to the last record in the database in the middle of the Do loop but uses the BookMark property to establish and reset current record positioning.

Listing C: Corrected record-reading code

Sub Form_DblClick ()

' clear the form
form1.Cls

' open the database
Dim dbBiblio As Database
Set dbBiblio = OpenDatabase("C:\VB\BIBLIO.MDB", True, ÂFalse)

' open the table
Dim tbAuthor As Table
Set tbAuthor = dbBiblio.OpenTable("Authors")

' start at the top
tbAuthor.MoveFirst

' define the bookmark
Dim bmCurrentAuthor As Variant

' until end of file...
Do While Not tbAuthor.EOF

    ' save where we are
    bmCurrentAuthor = tbAuthor.BookMark

    ' print record information
    form1.Print tbAuthor!Author

    ' go somewhere else in the database
    ' to look up other information
    tbAuthor.MoveLast

    ' return to the previous current record
    tbAuthor.BookMark = bmCurrentAuthor

    ' go to the next record
    tbAuthor.MoveNext

Loop

' close table
tbAuthor.Close

' close database
dbBiblio.Close

End Sub

Looking closely at the code in Listing C, you'll notice that we still move to the end of the database (by issuing the MoveLast method) right in the middle of the record-scanning Do loop. Because we save the current record position in the bmCurrentAuthor variable and then restore that position using the BookMark property, the program produces the proper output. Figure C shows the final output of the program, which you can see looks just like that from our original error-free code.

Figure C Even though the program changes the current record positioning during the record-scanning Do loop, the program still displays the proper output, thanks to the BookMark property.

In the real world

Of course, your program probably won't just jump to the last record in the database right in the middle of a record-scanning Do loop. What usually happens is that your program calls a function during a Do loop, and that function moves the current record position. When that happens, your program would be quite difficult to repair without the BookMark property. You'd have to save enough actual information about the current record so that you could return to it by using the FindFirst-FindNext or MoveFirst-MoveNext methods.

Fortunately, you can simply store the current positioning information provided by the BookMark property in a Variant variable you declare yourself. To return to that position in the Table, Dynaset, or Snapshot object, simply set your object's BookMark property to the value you saved previously in the Variant variable.

Also, you'll probably want to add some error-checking code to your functions that use the BookMark property to establish and reset current record positioning, especially on multiuser databases. You'll want to do this because your program will generate a run-time error if it tries to return to a record that another user deleted.

Conclusion

The Table, Dynaset, and Snapshot objects provide the BookMark property, which allows you to store and reset the current record position. Because of the BookMark property, your programs are free to change the current record position and return to it later, allowing you to write much more complex database lookup programs.

This article is reproduced from the June 1995 issue of Inside Visual Basic for Windows. Copyright © 1993, The Cobb Group. All rights are reserved. Inside Visual Basic for Windows is an independently produced publication of The Cobb Group. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of The Cobb Group.

To contact The Cobb Group, please call (800) 223-8720 or (502) 491-1900.


Finding the Shortest Path Between Two Points

We'd like to thank Dr. Andrew Wright, from the University of Louisville Computer Information Systems Department, for lending technical advice to this article.

When commuter traffic companies such as air travel agencies or bus lines book your trip, they use software to determine the best route between your point of departure and your destination. Their software takes into account the number of people traveling on the particular vehicle, the amount of time involved, and the shortest distance between the two points, among other things. Thanks to an early computer scientist named E. W. Dijkstra, finding the shortest path between two points is a relatively easy process, though an involved one.

Dijkstra developed an algorithm commonly, and appropriately, called the Shortest Path Algorithm. If you've had formal training in computer science, you've probably encountered Dijkstra's algorithm. If you haven't crossed paths with the Shortest Path Algorithm, hold onto your hats. We're going to learn about this algorithm and discover its usefulness. We'll also show you a program that implements this algorithm, but first, let's see how it works.

Dijkstra's Algorithm

If you've looked in almost any computer science books that contain the Shortest Path Algorithm, you've probably seen something that you'd think only a person with an advanced degree in mathematics could decipher. Many books list the algorithm in cryptic codes that look something like this:

  1. [Initialization.] Set L(a) := 0. For all vertices x ¹ a, set L(x) := ¥. Let T be the set of vertices.
  2. [Done?] If z Î T, stop. (L(z) is the length of a shortest path from a to z.)
  3. [ Get next vertex.] Choose v Î T with the smallest value of L(v). Set T := T - {v}.
  4. [Revise labels.] For each vertex x Î T adjacent to v, set L(x) := min {L(x), L(v) + w(v, x)}.
  5. Go to step 2.

Although there is plenty to be said about brevity in our current Information Age, unless you're a mathematically trained person, the above notation probably doesn't make a lot of sense to you. Don't let the cryptic formula intimidate you, though. Once you convert the algorithm to plain terms, it is elegantly simple. Listing A shows the Shortest Path Algorithm in its basic algorithmic form.

DO
    Find the node N that hasn't been included and has the smallest distance.
   Mark node N as included (Included(N) = True)
   For each N2 that isn't included
      IF Weight(N2, N) > 0 THEN
         IF Distance(N) + Weight(N,N2) < Distance(N2) THEN
            Distance(N2) = Distance(N) + Weight(N2,N)
            Path(N2) = N
         END IF
      END IF
   Next N2
LOOP UNTIL all nodes are included

Listing A. Shortest Path Algorithm

The algorithm depends on an element called a weighted graph. A weighted graph is simply a graph that shows the distances between two points. The lines in a weighted graph that connect two points are called edges and each point in the graph is called a node. Each edge in the graph is assigned the distance between the two nodes it connects. For example, Figure A shows a map of the United States with paths connecting several cities, depicting shipping routes for MadeUp Trucking, Inc. We've assigned each path, or edge, the ground traveling distance between the two cities, or nodes, each edge connects.

Figure A. Any graph showing the distance between two points is a weighted graph.

Before the algorithm can work, you need to do some preliminary initialization of three arrays. We'll call these three arrays Included, Distance, and Path. All three arrays should be of integer type. However, we'll use Included to contain boolean data.

Assume that From is the point from which you want to start, To is where you want to go, and N is any other node. You initialize Included(From) to True and the rest of Included(N) to False. You initialize Distance(N) according to the rule shown in Figure B.

 | 0 if N = From
Distance | Weight(From,N) if Weight(From,N) <> 0
 | Infinity if N isn't connected to From by a direct path (if Weight(From, N) = 0)

Figure B. Initialize the Distance array according to this rule.

The Weight( ) function simply returns the distance between the two points you pass to it. If the two points are not connected by a direct path, then Weight returns the value 0. You then initialize the Path array according to the rule shown in Figure C.

Path(N) = | From if Weight(From,N) <> 0
 | Undefined if Weight(From,N) = 0

Figure C. Initialize the Path array according to this rule.

The ShortPath Program

Now, let's look at the Microsoft® Visual Basic® (VB) program that determines the shortest path to see what actually happens. Listing B shows the code for Form2, our program for finding the shortest path between two points. The ShortPath program uses four user-defined functions: AllIncluded( ), which checks to see whether all the nodes have been included; MinNode( ), which returns the unincluded node with the minimum distance; Weight( ), which returns the weight of the edge connecting two points; and Initialize ( ), which initializes our three arrays.

' [Declarations Section]
Dim NumNodes  As Integer
Dim Infinity  As Integer
Dim Street()  As StreetType
Dim Distance()  As Integer
Dim Path()  As Integer
Dim Included()  As Integer
Dim A_Show As Integer

'***************************************************
Function AllIncluded ()
RetVal = True             ' Assume all are included
For X% = 1 To NumNodes
    If Included(X%) = False Then RetVal = False
Next
AllIncluded = RetVal
End Function

'***************************************************
Sub Command1_Click ()
Unload Me
End Sub

'***************************************************
Sub Command2_Click ()
FindPath
End Sub

'***************************************************
Sub Command3_Click ()
A_Show = Not A_Show
Command3.Caption = IIf(A_Show, "Hide Arrays", "Show Arrays")
End Sub

'***************************************************
Sub FindPath ()
' Now, get data from file
For X% = 1 To NumStreets%
    Get #1, X%, Street(X%)
Next X%
s% = 0
t% = 0
' Convert city to number
For X% = 1 To NumCities%
    Get #2, X%, GetCity
    test$ = UCase$(LTrim$(Trim$(GetCity)))
    If UCase$(LTrim$(RTrim$(Source.Text))) = test$ Then s% = X%
    If UCase$(LTrim$(RTrim$(target.Text))) = test$ Then t% = X%
    If (s% <> 0) And (t% <> 0) Then Exit For
Next
If (s% = 0) Or (t% = 0) Then
    Beep
    MsgBox "*****  Location(s) not found **** " + IIf(s% = 0, Chr(13)
         + Source.Text, "") + IIf(t% = 0, Chr(13) + target.Text, "")
    Exit Sub
End If
Initialize s%, t%
'***
'* Begin Shortest Path function
spath$ = ""
Do
    If A_Show Then
        tt$ = ""
        For XX% = 1 To NumNodes%
            tt$ = tt$ + Format$(XX%, "00") & " " & Format$(Distance(XX%),
              "00000") & "  " & Format$(Path(XX%), "00") & "  " &
              Format$(Included(XX%), "00") + Chr$(13)
        Next
        If MsgBox(tt$, 1) = 2 Then   ' cancel
            command3_click
        End If
    End If
    j% = MinNode()
    Included(j%) = True
    For X% = 1 To NumNodes
        If Included(X%) = False Then
            ' Prevent overflowing on any system
            If (Weight(j%, X%) < Infinity) And (Distance(j%) <
                Infinity) Then
                If Distance(j%) + Weight(j%, X%) < Distance(X%) Then
                  Distance(X%) = Distance(j%) + Weight(j%, X%)
                    Path(X%) = j%
                End If
            End If
        End If
    Next
Loop Until AllIncluded() = True
j% = t%
spath$ = LTrim$(RTrim$(Str$(j%)))

Do
    X% = Path(j%)
    spath$ = LTrim$(RTrim$(Str$(X%))) + ", " + spath$
    j% = X%
    If X% = -1 Then
        MsgBox "No Path Possible"
        Exit Sub
    End If
Loop Until (X% = Path(X%))
list1.Clear
list1.AddItem "The Shortest Path between the two is:"
location = InStr(spath$, ",")

Do While location > 0
    t% = Val(Mid$(spath$, 1, location - 1))
    Get #2, t%, GetCity
    list1.AddItem "---- " & GetCity
    spath$ = Mid$(spath$, location + 1)
    location = InStr(spath$, ",")
Loop
t% = Val(spath$)
Get #2, t%, GetCity
list1.AddItem "---- " & GetCity
Mileage.Caption = Distance(t%)
Source.SetFocus
End Sub

'***************************************************
Sub Form_Load ()
NumNodes% = NumCities%
Infinity = 32767
Source = String$(20, " ")
Target = Source
ReDim Street(1 To NumStreets%)   As StreetType
ReDim Distance(1 To NumNodes%)  As Integer
ReDim Path(1 To NumNodes%)  As Integer
ReDim Included(1 To NumNodes%)  As Integer
A_Show = True
End Sub

'***************************************************
Sub Initialize (s%, t%)
For X% = 1 To NumNodes%
    Wgt% = Weight(s%, X%)
    Distance(X%) = Wgt%
    If s% = X% Then
        Included(X%) = True
    Else
        Included(X%) = False
    End If
    If Wgt% >= 0 And Wgt% <> Infinity Then
        Path(X%) = s%       ' source
    Else
        Path(X%) = -1
    End If
Next
End Sub

'***************************************************
Function MinNode ()
'* Searches the unincluded nodes for the shortest distance and returns
'* that node's number. Requires global arrays Included() and Distance()
Dim temp As Integer
min% = Infinity     ' Max number for Integer
For X% = 1 To NumNodes
    If Included(X%) = False Then        ' Not included
        temp% = X%
        If Distance(X%) < min% Then
            min% = Distance(X%)
            node% = X%
        End If
    End If
Next
If min% = Infinity Then
    node% = temp%
End If
MinNode = node%
End Function

'***************************************************
Function Weight (Source%, j%)
'* Returns the weight, or distance, between the two nodes Source and j.
'* If Source is the same as j, Weight returns 0. If the two nodes
'* aren't connected by a path, Weight returns Infinity.
RetVal = 0
If j% = Source% Then
    Weight = 0
    Exit Function
End If
For X% = 1 To UBound(Street)
    If (Street(X%).from = Source% And Street(X%).to = j%) Or
           (Street(X%).from = j% And Street(X%).to = Source%) Then
        RetVal = Street(X%).Wgt
        Exit For
    End If
Next
If RetVal = 0 Then
    RetVal = Infinity
End If
Weight = RetVal
End Function

Listing B. The Shortest Path program

After you choose the Find Shortest Path button from our demonstration form shown in Figure D, our shortest path system executes the code found in Listing C, which is stored in the system's module. We called the module SHORTPAT.BAS. The code in the module declares the type StreetType, which houses the structure for our street records (From, To, and Wgt). The module code also declares several other variables and opens the files we'll use in our system. Notice that we also calculate the number of records in each file (NumCities% and NumStreets%). These values are required for our algorithm to function properly.

Figure D. This is the main form in our Shortest Path demonstration.

Type StreetType
    From As Integer
    To As Integer
    Wgt As Integer
End Type
Dim Street As StreetType
Global GetCity As String * 20
Global FromCity As String * 20
Global ToCity As String * 20
Global TString As String * 20
Global NumCities As Integer
Global NumStreets As Integer
Global fCity As String * 20
Global tCity As String * 20
Sub MainInit ( )
RecSize% = Len(Street)
Open "i:\articles\VBW\ivb0395\street.dat" For Random Access Read Write
       Lock Read Write As #1 Len = RecSize%
NumStreets% = LOF(1) / RecSize%
GetCity = String$(20, " ")
RecSize2% = Len(GetCity)
Open "i:\articles\VBW\ivb0395\City.dat" For Random Access Read Write
       Lock Read Write As #2 Len = RecSize2%
NumCities% = LOF(2) / RecSize2%
End Sub

Listing C. The module SHORTPAT.BAS

The Form_Load( ) event—back in Listing B—then initializes a couple more variables. The variable NumNodes% stores the number of cities (or nodes) on file. Since we don't have an Infinity value in VB, we assign a large number to the variable Infinity. The function then declares and initializes the three arrays we previously mentioned. You'll see that we dimension the array Street using NumStreets%, since it stores the number of streets (or edges). Next, we initialize a logical variable A_Show, which we'll use to show us how the arrays' values change through each iteration.

Once you load this form, you'll see that the system is waiting for you to enter two locations: a starting point and a destination. Using Figure E as an example, suppose you want to ship a package from Topeka, Kansas, to Louisville, Kentucky. Enter Topeka as the Starting Point and Louisville as the Destination. Then, click the FindPath button to start the search for the shortest path between these two cities.

Figure E. Our Find Shortest Path form lets you enter a starting point and a destination; then it calculates the distance of the shortest path between those two points.

The FindPath Subroutine

FindPath first fills the Street array with data. When the For-Next loop finishes, Street will contain every From-To-Wgt combination we have on file. The subroutine then initializes the variables s% and t%, which will contain the numbers of the cities you entered.

We naturally refer to the cities on our map by their names. The algorithm, however, works better by referring to the cities as numbers. FindPath's routine converts the cities' names to numbers for us. If the Source or Target city is found on file, that city's record number is stored in either s% or t% for source or target, respectively (remember the city's record number is the index used in STREET.DAT).

If either s% or t% is equal to zero after the file search, that means one of the cities hasn't been found. FindPath informs you and loops back for data re-entry.

Next, FindPath calls the Initialize( ) routine. After initialization, ShortPat's three arrays look similar to the ones in Figure F. You can see that all the X data is in numeric form. There are no city names listed because the record number shown in column X represents the city. That is, each X number is the index for a particular city in CITY.DAT. (If you'd like to stop tracing through the arrays as each iteration completes, you can click the Hide Arrays button. This disables the function that displays a list—for reference purposes only—similar to the one in Figure F.

x | Distance | Path | Included
1 | 32767 | -1 | 0
2 | 32767 | -1 | 0
3 | 32767 | -1 | 0
4 | 557 | 8 | 0
5 | 32767 | -1 | 0
6 | 32767 | -1 | 0
7 | 32767 | -1 | 0
8 | 0 | 8 | -1
9 | 514 | 8 | 0
10 | 32767 | -1 | 0
11 | 32767 | -1 | 0
12 | 578 | 8 | 0
13 | 32767 | -1 | 0
14 | 32767 | -1 | 0
15 | 32767 | -1 | 0
16 | 32767 | -1 | 0
17 | 32767 | -1 | 0
18 | 32767 | -1 | 0
19 | 32767 | -1 | 0
20 | 32767 | -1 | 0
21 | 32767 | -1 | 0
22 | 32767 | -1 | 0
23 | 32767 | -1 | 0
24 | 32767 | -1 | 0

Figure F. The three arrays ShortPat uses look like this after initialization with our sample data.

This month's Software Developer's Resource Disk contains our sample data. So, if you look at record 8 in CITY.DAT, you'll see that Topeka is the city name. Table A shows the city index table for the sample data. You can generate your own listing by using the Add City option of our Shortest Path Demonstration form, shown in Figure D earlier in this article.

Table A. This is the city index table, CITY.DAT, for our sample data.

City | Index | City | Index
Los Angeles | 1 | Des Moines | 13
Carson City | 2 | Milwaukee | 14
Salt Lake City | 3 | Lansing | 15
Denver | 4 | Louisville | 16
Phoenix | 5 | Pittsburgh | 17
Helena | 6 | New York | 18
Bismarck | 7 | Atlanta | 19
Topeka | 8 | Nashville | 20
Dallas | 9 | Birmingham | 21
Austin | 10 | Tampa | 22
Jackson | 11 | Jacksonville | 23
Chicago | 12 | Miami | 24

If any node is connected to the starting point, or Source node, the Distance array contains the distance from Source to that node. For example, Distance(4) contains 557, which is the distance from Topeka to Denver, as you can see in Figure A. Likewise, Distance(9) contains 514—the distance from Topeka to Dallas. Since there is no direct path from Topeka to Louisville, Distance(16) contains our value for infinity.

The program initializes all paths to the Source variable if an edge exists between the Source and the node. Otherwise, FindPath assigns the value -1 (for undefined, in this case) to the path. The Included array contains a logical True for our Source node and a logical False for all others.

Next, the program initializes the SPath$ variable to null and enters a DO loop. The routine then checks to see whether it should show the iteration's array values. If so, it builds a string, then displays the string using the MsgBox( ) function.

FindPath uses the variable j% to act as another node counter. The FindPath program first assigns the node with the minimum distance to j% by calling the function MinNode( ). Following the algorithm, the program marks this node as included. Then, the program checks the weights (distances) between all the unincluded nodes and the MinNode node. If the value stored in Distance(j%) plus the weight of the edge between the new nodes is less than the distance stored for the unincluded node, then the shorter distance is stored. Finally, the program updates Path(unincluded node) with the MinNode value. Path(X) always contains the last node visited before X.

Let's clear things up a bit. If you look at Figure G, you'll see what the data arrays look like after the first iteration of the DO loop. Since, from Figure F (above), node 9 contains the smallest distance of all the nodes not yet included, FindPath uses it as the MinNode value and then marks it included with a value of .T.. Next, the program checks the distances between node 9 and the rest of the unincluded nodes to see whether it can find a shorter path.

x | Distance | Path | Included
1 | 32767 | -1 | 0
2 | 32767 | -1 | 0
3 | 32767 | -1 | 0
4 | 557 | 8 | 0
5 | 32767 | -1 | 0
6 | 32767 | -1 | 0
7 | 32767 | -1 | 0
8 | 0 | 8 | -1
9 | 514 | 8 | -1
10 | 713 | 9 | 0
11 | 933 | 9 | 0
12 | 578 | 8 | 0
13 | 32767 | -1 | 0
14 | 32767 | -1 | 0
15 | 32767 | -1 | 0
16 | 32767 | -1 | 0
17 | 32767 | -1 | 0
18 | 32767 | -1 | 0
19 | 32767 | -1 | 0
20 | 32767 | -1 | 0
21 | 32767 | -1 | 0
22 | 32767 | -1 | 0
23 | 32767 | -1 | 0
24 | 32767 | -1 | 0

Figure G. This is the state of the arrays after the first iteration of the DO loop.

In our example, the program doesn't find a shorter path until it checks node 10. Since the distance from Topeka through Dallas to Austin—713 miles—is shorter than Infinity, ShortPat stores the new value in Distance(10)—10 is the index for Austin. It then stores the MinNode value—9— in Path(10) and proceeds with the rest of the loop in like manner.

When the program finishes, the arrays contain data like that shown in Figure H. You can see that all the nodes are now marked included, which is the condition under which the program terminates. If you follow the trail from your destination node, in this case, Louisville—Path(16)—you'll end up at Path(8), which is the index for Topeka. To see what we mean, check Path(16). It refers you to 12, which is Chicago. Now check Path(12). It refers you to Path(8), which is Topeka. Path(8) refers to itself, so you know your path-finding is finished. The total distance for the trip is stored in the Distance node for your destination. So, checking the Distance array for Louisville, Distance(16), you see that 875 is the length of the trip, which Figure E (earlier in this article) shows.

x | Distance | Path | Included
1 | 1751 | 4 | -1
2 | 2205 | 1 | -1
3 | 1075 | 4 | -1
4 | 557 | 8 | -1
5 | 2143 | 1 | -1
6 | 1395 | 4 | -1
7 | 1282 | 4 | -1
8 | 0 | 8 | -1
9 | 514 | 8 | -1
10 | 713 | 9 | -1
11 | 933 | 9 | -1
12 | 578 | 8 | -1
13 | 920 | 12 | -1
14 | 666 | 12 | -1
15 | 783 | 12 | -1
16 | 875 | 12 | -1
17 | 1042 | 12 | -1
18 | 1410 | 17 | -1
19 | 1317 | 16 | -1
20 | 1574 | 16 | -1
21 | 1484 | 19 | -1
22 | 1788 | 19 | -1
23 | 1988 | 22 | -1
24 | 2057 | 22 | -1

Figure H. ShortPat terminates after it includes all nodes. Upon termination, the arrays look like this.

Creating the Data Files

The program isn't functional without data files in the proper format, so we've included a form entitled Add City and Distance to File that lets you create them. The code for the form, shown in Listing D, asks you for two points and the distance between them. It checks to see whether the cities you've entered are already in the CITY.DAT file. If they aren't, the code adds the cities. If they are, the code uses their index numbers to build STREET.DAT. The CITY.DAT file contains one city name per record. The STREET.DAT file contains two city index numbers and a distance per record.

'[Declarations Section]
Dim street As StreetType
Dim Tstring As String * 20

'***************************************************
Sub Command1_Click ( )
MsgBox "There should be " & NumCities% & " cities on file."
Unload Me
End Sub

'***************************************************
Sub Command2_Click ( )
X% = 1
If LOF(2) > 0 Then
    street.from = 0
    street.to = 0
    Do
        Get #2, X%, GetCity
        If Not EOF(2) Then
            Test$ = UCase$(LTrim$(RTrim$(GetCity)))
            If UCase$(LTrim$(RTrim$(FromCity.Text))) = Test$ Then
                 street.from = X%
            If UCase$(LTrim$(RTrim$(ToCity.Text))) = Test$ Then
                 street.to = X%
                X% = X% + 1
        End If
    Loop Until EOF(2) Or ((street.from <> 0) And (street.to <> 0))
End If
'*) if we've reached EOF( ) and either street record is 0, then the
'*) city isn't on file
If street.from = 0 Then
    Tstring = Mid$(FromCity.Text, 1, 20)
    Beep
    MsgBox "Adding city " & Tstring
    Put #2, X%, Tstring
    street.from = X%
    X% = X% + 1
End If
If street.to = 0 Then
    Tstring = ToCity.Text
    Beep
    MsgBox "Adding city " & Tstring
    Put #2, X%, Tstring
    street.to = X%
End If
street.Wgt = Val(Distance.Text)
NumStreets% = NumStreets% + 1
Put #1, NumStreets%, street
List1.AddItem FromCity.Text & "  " & ToCity.Text & "  " & street.Wgt
List1.ListIndex = List1.ListCount - 1
FromCity.SetFocus
End Sub

'***************************************************
Sub command3_click ( )
ListCity
End Sub

'***************************************************
Sub Form_Load ( )
FromCity.Text = GetCity
ToCity.Text = GetCity
ListCity
End Sub

'***************************************************
Sub ListCity ( )
RecSize% = Len(street)
NumStreets% = LOF(1) / RecSize%
List1.Clear
For X% = 1 To NumStreets%
    fCity = String$(20, " ")
    tCity = String$(20, " ")
    Get #1, X%, street
    f% = street.from
    t% = street.to
    Get #2, f%, fCity
    Get #2, t%, tCity
    List1.AddItem Left(fCity, 15) & " " & Left(tCity, 15) & " " &
        street.Wgt
Next X%
GetCity = String$(20, " ")
RecSize2% = Len(GetCity)
NumCities% = LOF(2) / RecSize2%
MsgBox "There are currently " & NumCities% & " cities and " &
     NumStreets% & " streets on file."
End Sub

Listing D. Add City and Distance to the form's Code

So What Good Is It?

The Shortest Path program obviously fills the bill quite well for an application like the one we've presented here. However, it doesn't have to be used only for finding the shortest travel distances. You may wish to assign the cost of plane tickets to the edges of your own graph. Then, you could determine the cheapest route from Helena, Montana, to Miami, Florida. Or, perhaps you may decide to let the edges represent project roads and their weights equal the cost of building the road. This could tell you the most economical route to build. In a situation in which you're experimenting with several hundred vertices, you can see how this program would come in handy.

You'll find all the files from this article on this month's Software Developer's Resource Disk. To order the disk, call Customer Relations at (800) 223-8720.

This article is reproduced from the March 1995 issue of Inside Visual Basic for Windows. Copyright 1995, The Cobb Group. All rights are reserved. Inside Visual Basic for Windows is an independently produced publication of The Cobb Group. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of The Cobb Group. To contact The Cobb Group, please call (800) 223-8720 or (502) 491-1900.


Ask Dr. GUI #25

(Remember, he's not a real doctor. In fact, he's not even a he.)

August 1995

Have a question? Dr. GUI's busy operating schedule won't allow her to answer all questions, but the Good Doctor will answer as many as she can in the next release of the Microsoft Development Library. Send your questions to:

Dr. GUI
Microsoft Developer Network
One Microsoft Way
Redmond, WA 98052-6399

Fax: (206) 936-7329, Attn: Developer Network
Internet: msdn@microsoft.com

CH-CH-CH-Changes: BackOffice Tools

It's a strange world. One day you put your faith in some guy who calls himself a doctor (but he really isn't). You can handle this. I mean, what's a little white lie between friends. Then, the next day, you find out that not only isn't the doctor a real doctor, but he isn't even a man! You wonder: Has my hero had one of those operations that people talk of in hushed voices? Have I been hornswoggled? Is hornswoggled a word? (Yes, it is.)

Well, there's no need to panic. The answer's really very simple. Those of you who are fans of the BBC television show "Dr. Who" are aware of an interesting anomaly that occurs every so often: The doctor regenerates into a new form. Usually this happens when the good doctor finds himself in a situation where, were he a normal human being (and not a time lord), he would die. Time lords don't die. They regenerate. Similarly, Dr. GUI didn't move on to do something more interesting and profitable—he regenerated. Now he's a she and, like her previous incarnation, she's not a real doctor. She does, however, golf on Wednesdays whenever possible.

Questions in this issue:

Mama, Don't Let Your Babies Grow Up to Be BackOffice Developers

Who's Touching My Files?

What We Have Here Is a Failure to Communicate

Dynamic, Resource-Free Dialogs

Tab Controls and Visual Basic

I Have DIBs on That!

Metafiles and Scaling


 Mama, Don't Let Your Babies Grow Up to Be BackOffice Developers

Dear Dr. GUI:

I am just itching to start work on BackOffice development, but I have a couple of questions. When will the tools necessary to develop good BackOffice applications be available on MSDN? What is the plan for the BackOffice SDK?

A BackOffice developer wannabe

Dr. GUI replies:

An itch, eh? Have you tried a good moisturizer or some baby powder? How about some of that Gold Bond Medicated Cream for that itchy, itchy rash? Well, not being a real doctor, I'm not sure that I can help with the itch, so an answer to your two questions will have to suffice.

If by tools you mean products such as Visual Basic and Visual C++, those are not available from the Developer Network. However, your question is timely (unlike my office hours!) because the Developer Network has just announced the availability of Level 3. This new level features the BackOffice Test Platform, which will include all the BackOffice server components you've come to know and love—SQL Server, Systems Management Server, Windows NT Server, SNA Server, and Mail (or Microsoft Exchange) Server.

In other relevant news, my nursing staff informs me that the BackOffice SDK was shipped to Level 2 members in late August with Windows 95 and the Win32 SDK. Whew! That was a lot of info to impart. Now I have a headache. I'm going to take two aspirin and call myself in the morning.


 Who's Touching My Files?

Dear Dr. GUI:

I realize my question is not about the graphical interface, but I will ask it anyway. I have an application for Windows NT that has a need to know who is accessing particular files (I hope to then inform the individuals to get off, but that is a different issue). What would be the best approach to accomplish this? I figure it should be able to be done similarly to the way File Manager has the Open By button on the File/Properties option.

Thank you,
Rick Kellough
Severna Park, Maryland

Dr. GUI replies:

Dr. GUI will answer non-GUI questions. You just won't get any fun humor to go along with the answer.

File Manager goes through the security layer. Because Windows NT has built-in security, it is possible to both monitor and control access to objects, including files, in a Windows NT Server application. (You should take a look at the excellent series of articles on security written by Ruediger Asche in the Microsoft Development Library.)

Security works on a multitude of levels, and, while File Manager goes through security in the network layer, it is also possible to assign auditing and security information to individual files on an NTFS partition. The one thing you CANNOT do using security, however, is to dynamically assign actions to be taken as soon as a particular file is accessed. If you need to do that, you will have to write a kernel-mode device driver that sits on top of the file system driver and looks at the incoming Open/Close/Read/Write calls before the "real" file system driver sees it.


 What We Have Here Is a Failure to Communicate

Dear Dr. GUI:

I'm using Visual C++ 1.5. My application has a dialog box that creates another dialog box (while the first dialog box is still active). What I want to do is pass data from/to my document and the second dialog. Unfortunately, I'm not in the view, so I can't use GetDocument to get the pointer to the document.

What I'm doing now is to store the pointer to the document in the dialog before I activate it from the view using GetDocument. Then when I'm in the dialog I can use the pointer I had previously stored in the dialog to access the data.

There must be an easier way to get a dialog view so I can use something like GetDocument instead of having to store the pointer in the dialog. Can you help? Thanks.

Joe Mintzer
Gilbert, Arizona

Dr. GUI replies:

I am so glad that you came to me for the answer. There is, indeed, an easier way to do this. Just pass a pointer to your view window to the constructor for your CDialog-derived dialog box. From within the dialog box, you can call CWnd::GetParent to get a CWnd pointer to the view class as follows:

CMyDialog MyDlg(&MyView) ;
CWnd* pMyView = MyDlg.GetParent() ;

Voilà! You now have the pointer you need to make your call to GetDocument.


 Dynamic, Resource-Free Dialogs

Dear Dr. GUI:

I am building an application that requires dynamically configured dialog boxes. I am developing under the Windows API (as opposed to the Foundation classes), and I have not found any mechanism for creating such dynamic dialog boxes "on the fly." My current implementation uses CreateWindow to build the window, but with that approach I don't get the default dialog processing. (This approach also produces several other problems and some nonconforming GUI behaviors.)

Is there an easy way to create arbitrary modal and nonmodal dialog boxes dynamically without using resources?

Bob Kuczewski

Dr. GUI replies:

You can use the CreateDialogIndirect function to create dialog boxes dynamically. This function uses the CreateWindowEx function to create a modeless dialog box from a dialog template in memory. CreateDialogIndirect then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box if the template specifies the WS_VISIBLE style. Finally, CreateDialogIndirect returns the window handle of the dialog box.

After CreateDialogIndirect returns, the application displays the dialog box (if it is not already displayed) by using the ShowWindow function. The application destroys the dialog box by using the DestroyWindow function.


 Tab Controls and Visual Basic

Dear Dr. GUI:

We are currently developing various client-server applications using Visual Basic 3.0. In the client development, we would like to improve the look and feel by including the new look for options as appears in Microsoft Excel 5.0 and Word 6.0. This new look appears like the tabs of a folder. On the same window, the user can select a tab, and a new set of options appears in a frame in the same window.

The question I have is:

1. Is there a custom control that is an enhancement on the existing frame control currently available to provide this new look?

2. If not, is there a custom control planned for the next release of Visual Basic?

Regards
Dan O'Riordan
Jean Michel Becar

Dr. GUI replies:

Actually, that was two questions, but my investments are doing well today and I am feeling overly generous right now, so I'll answer both.

It sounds like you want to include a property sheet in your applications. The good news is that there are already a variety of custom controls that provide this look. One in particular is called Yet Another Tab Control (YATC.VBX), and it is available in the Development Library.

As you may know, Visual Basic 4.0 (due out this fall) supports OLE Controls, and you will find a tab OLE Control called TABS.OCX on CompuServe.

I guess you two will have to share the T-shirt.


 I Have DIBs on That!

Dear Dr. GUI:

I am working on a real-time simulation involving DIBs and need to combine two DIBs in memory, then put it on the screen. I have tried different versions of the SetDIBitsToDevice function and the BitBlt function. What is the fastest method of combining two DIBs in memory, and then copying it to the screen?

Thank you,
Kathleen Wilson

Dr. GUI replies:

The best way is to manipulate the bits of the DIBs (device-independent bitmaps) directly yourself. Since you know where the memory is, and the organization of a DIB is published in the SDK documentation, it's a simple matter to get a pointer to any pixel. Having combined your images using whatever composition algorithm you choose, you can copy the composite image to the screen using StretchDIBits with the DIB_RGB_COLORS option. This is by no means the fastest way, but it is simple. You should note that if you combine images, you'll also need to combine their color tables.


 Metafiles and Scaling

Dear Dr. GUI:

I must display graphic information in such a way that the user can scale and move the drawing interactively. For some reason, I decided the best way is to store my graphical information in a metafile; the visualization mechanism takes care of playing this metafile in the screen context, after preparing an MM_ANISOTROPIC mapping mode with the window and viewport origin and extents set properly. This works fine.

I must include, as part of my graphical information, a metafile. The metafiles are Aldus placeable metafiles, but my problem is that they include records as SetWindowExt and SetWindowOrg (and possibly even SetViewportExt and SetViewportOrg). I save my mapping mode and metrics with SaveDC and RestoreDC, but the included metafile always appears with the same position and size.

How can I force such a metafile to draw itself in a position and size controlled by my own initial calls to Set...Ext and Set...Org, as the rest of the elements I draw?

Thank you very much, doc. (A T-shirt will be appreciated.)

Regards,
Alfredo Moran

Dr. GUI replies:

They always render the same size. The placeable metafile was designed to address WYSIWYG concerns. It worked well but has always been confusing to developers. The ultimate solution is to use enhanced metafiles (EMF). There are Win32 functions that convert older-style Windows metafiles (WMF) to EMF. But this still does not address all issues associated with placeable metafiles.

The problem you are encountering is the tight coupling between the window origin and extents (that are included in the metafile), and the boundaries and extents used in the subsequent metafile records. The only way to decouple these effectively is to enumerate the metafile and skip over any coordinate mapping records. However, you will want at least to observe what was going on in these records, because you will need to set your own coordinate mapping system to achieve the scaling you are looking for. It is better to do this than adjusting the parameters of all subsequent records.


Focusing on Accessibility Barriers

Gregory C. Lowney

November 1, 1995

Everyone wants his or her product to attract as many users as possible. But many programs unintentionally put up barriers that prevent some customers from employing them enjoyably or efficiently—even, in some cases, making them impossible to use. This problem is most pronounced for computer users who have disabilities.

Software design decisions can either make it easy for these users or drive them to competitive products. Your business customers may standardize on a competitive product even if they employ relatively few people with disabilities, and you could even put some of your customers in violation of anti-discrimination laws. When your product is friendly for people with disabilities, it is also addressing the needs of their friends, family, coworkers, and employers.

This new column on accessibility discusses how you can identify barriers in your designs, and how, with very little work, you can make your products more accessible and more usable.

An increasing number of people are interacting with applications by using software assistants, utilities that filter or automate different types of interaction. For example, voice-input utilities are used by executives, doctors, machinists, and others who need to operate the computer while their hands are busy. Such utilities are a necessity for people whose disabilities make it difficult for them to use the mouse, keyboard, or display. Among these are people with repetitive stress injury (RSI), one of the fastest-growing categories of disability. Other people use keyboard macro packages, word-prediction packages that speed typing, screen-magnification utilities to relieve eyestrain or compensate for low vision, or even audio software that describes the contents of the screen to make it accessible to people who are blind or people accessing their computer over a telephone. Making sure an application is compatible with accessibility aids is a key factor in making it accessible.

Indicating the user's point of focus

Many accessibility aids need to identify the "focus point," where the user is working. For example, a blind-access utility must describe the text or object the user is working on, and a screen-magnification utility pans to enlarge whatever is at that point on the screen. Other utilities may move pop-up windows so they avoid covering "where the action is."

Sometimes it's easy for a utility to determine this location; the operating system provides it when moving the focus between windows, menus, or standard controls. The difficulty comes when an application uses a private method of indicating the visual focus within its window, such as highlighting a cell in a spreadsheet, an icon, or a windowless custom control. In these cases, to be accessible, the application must make its focus location available to other programs in the system; the convention for doing this is to move the system caret.

Moving the system caret

The system caret is the blinking vertical bar that's seen when you're editing text, but it can be placed anywhere on the screen and made any shape or size. It can even be made invisible—it can be moved to indicate the focus region to programs without disturbing what the user sees on the screen.

Doing this is easy: simply call CreateCaret to set the caret's size and shape, and SetCaretPos to move it to wherever you're drawing the visual focus indicator (the highlighted cell, icon, button, and so on). Remember, it's present but invisible unless you explicitly say otherwise.

Applications should only display focus and selection indicators when they're the active window. When you lose activation, remove the visual indicator and also call DestroyCaret to inform other programs. (For Win32-based applications, this is not strictly necessary, but is still good practice.)

Where is the keyboard focus?

Sometimes it seems hard to decide what you should indicate as the focus location. Extended and discontiguous selection often confuse the issue, but the real answer is pretty simple: The keyboard focus location should be considered independent of selection, even if your application normally links the two.

The following examples may clarify the distinction and help you learn to identify and indicate the keyboard focus location in your own application:

• Insertion bars in text. When the user is moving an insertion point within text, it's usually drawn with the real system caret. If the application chooses to draw its own insertion point, it should still move the system caret invisibly, tracking the location of the visible insertion bar.

• Extended text selection. When you make an extended selection, one end of the selection is always the "active" or moving end, and that's the actual location of the keyboard focus. For example, starting with the insertion bar in an edit control, hold down the SHIFT key while pressing the right arrow twice; you now have three characters selected. The end where you started is the "anchor," or stationary end; at the right you should see the flashing caret marking the active end. If you hold down SHIFT and press another arrow key, it's the active end that moves; that's where the system caret should be placed. Don't forget to display a visible insertion bar at the active end, because that's useful feedback for all users.

• On graphic objects. When a user moves the keyboard focus to a graphic object, such as an icon or a bitmap, an application should place the system caret invisibly over the same object so that the caret's rectangle covers the entire image. If there's an adjacent label, the caret should cover that as well.

• Within graphic objects. Sometimes an application uses a single bitmap to represent several objects, such as a group of graphical buttons. Such applications usually indicate the focus by highlighting a portion of the bitmap, or drawing a dotted rectangle over it, or even moving the mouse pointer. In these cases it should also place the system caret, invisibly, over the region of the bitmap that corresponds with the "hot spot" or object being referenced.

• Simple controls. If an application is drawing simple custom controls, such as a custom push button, the keyboard focus is associated with the entire control, so the entire control should be covered by the system caret. (This is necessary only for windowless custom controls; if the control is a window, that window takes the keyboard focus, so it's not necessary to identify it using the system caret.)

• Complex controls. A complex or composite control, such as a list box, can place the focus on individual elements within the larger control. In this case, use the system caret to indicate the area of the particular item that has the focus. Even though the application might think of the collection of items as a single control, they should be treated as separate control elements when identifying them to external components.

• Spreadsheets. When navigating within a spreadsheet, one normally puts the focus on an entire cell, rather than on content within the cell. Often this is indicated by giving the cell a bold border; the application should place the system caret over the entire cell. If the user begins editing the contents of a cell, indicate the focus appropriately for the content text or graphics.

• Discontiguous selection. Discontiguous selection is usually supported among discrete items, rather than in text. There's always one item that has the keyboard focus or was most recently clicked with the mouse, and that object should be covered by the system caret. To see an example, select an item in a folder or in File Manager, then hold down the CTRL key while pressing arrow keys to move the focus rectangle to a file that isn't part of the selection.

• Mouse-only objects. While applications should provide keyboard access to all their functionality, sometimes you have objects that can only be manipulated or selected with the mouse. In this case, treat the object when it's selected as if it received the keyboard focus, and use the system caret to indicate it appropriately. Of course, if the real keyboard focus is moved, follow it, since the mouse-only object is no longer the object of the user's attention.

Does it work?

If you do it right, moving the system caret is one of the simplest and most effective ways to make your application compatible with a wide range of accessibility aids. You can test it by using the CARET and CARET32 tools that are planned for an upcoming release of the Microsoft Development Library. These tools will show you where the system caret is at all times. Future releases will provide more guidelines on accessible software design, and possibly even demonstration versions of commercial utilities that rely on this technique.

We recognize that this method is not effective for some multithreaded applications, and under Win32 it's not as easy for accessibility aids to track. So, in the works is a new standard, called OLE Accessibility, that will provide a more sophisticated mechanism for publishing information about your focus and selection. Watch for it in future columns on accessibility.

Greg Lowney founded and manages Microsoft's Accessibility and Disabilities Group. Previously, he was senior program manager responsible for the Windows 3.1 core components.


Getting Ready for Windows Sockets Version 2

Martin Hall

November 1, 1995

Windows Sockets architecture

Windows Sockets—or "WinSock" as it has become known—is the open, transport-level network API standard for the Windows operating system. Designed by the WinSock Group, a coalition of independent software vendors (ISVs), Windows Sockets are now utilized by most Internet and client/server TCP/IP applications as their key to the network.

Windows Sockets version 1.1 was published in January 1993. It focused on providing a Berkeley Software Distribution (BSD) 4.3 sockets API for TCP/IP. Developers of TCP/IP and Internet applications use this as a standard programming interface to create software capable of running on any vendor's Windows-based implementation of TCP/IP. Network stack vendors providing implementations of Windows Sockets today include Microsoft, CompuServe, Novell, WRQ, FTP Software, NetManage, SunSoft, Beame & Whiteside, Wollongong, Persoft, and many more.

As remote connectivity has become more important for mobile corporate and home users, dial-up Windows Sockets implementations have become increasingly prevalent from vendors such as NETCOM, Quarterdeck, CompuServe, and Netscape.

The Windows Sockets version 2 spec

The Windows Sockets Group, which was formed in 1991, meets several times each year to refine and extend the specification and to hold interoperability testing sessions—forums in which software developers test the interoperability of their applications with vendors' Windows Sockets-enabled transports.

For the past 18 months, the Windows Sockets Group, which consists of application, network, and operating system software vendors and developers, has been working on expanding the specification to support many additional communications capabilities. The Windows Sockets version 2 provisional specifications were published several months ago, and the beta software development kit (SDK) is scheduled for availability in early December.

Today, several hundred developers contribute to the definition of the specification by means of the winsock2@mailbag.intel.com mailing list. Some of the key contributors to version 2 are Microsoft, Intel, Stardust Technologies, FTP Software, Novell, Motorola, DEC, and ICL.

As the specification process nears completion, communications software developers should start to examine the ways in which they can exploit the new features of Windows Sockets version 2. This article introduces the new features and architecture of version 2, and discusses some of the opportunities it creates for developers.

New architecture

To provide backward compatibility, the version 2 architecture includes 16-bit and 32-bit dynamic-link library (DLL) implementations of Windows Sockets version 1.1. The APIs are a superset of the previous version, which means that a simple relink is the first step in migrating from version 1.1 to version 2.

Because of the support for multiple network transports and name/service resolution mechanisms, the Windows Sockets 2 architecture has changed. As the figure at the top of this file shows, the architecture for Windows Sockets 2 divides the Windows Sockets subsystem into two general layers: the DLLs providing the Windows Sockets APIs and the service providers that plug in underneath the DLLs through the Service Provider Interface (SPI).

The Windows Sockets 2 definition includes three separate specifications: Windows Sockets 2 API definition, Windows Sockets 2 SPI definition, and the Transport Protocol-specific Annex.

The Windows Sockets 2 DLL (WS2-32.DLL) incorporates all the APIs used by application developers. This includes the existing Windows Sockets 1.1 APIs, semantically unchanged, plus new APIs for enhanced data communication facilities and generalized name service APIs.

Multiple vendors now provide concurrent access to their own transports by creating a service provider that conforms to the Windows Sockets 2 SPI definition. This means that you can develop an application that can access, for example, both TCP/IP and IPX/SPX simultaneously through the new API.

The name space SPI allows multiple name resolution services to be accessed through a uniform API. As vendors create service providers for DNS, NetWare Directory Services, and X.500, all their name resolution capabilities will be accessible through the Windows Sockets 2 name space APIs.

New functionality

New functionality in Windows Sockets 2 includes:

Advanced performance capabilities. Version 2 enables the development of very fast 32-bit client and server applications. Support for overlapped I/O cuts down on buffer transfers and CPU cycles, and provides substantial performance benefits. Used in conjunction with Win32 event objects, it provides extremely fast, multithreading-capable data transfer capabilities.

Name resolution. Many name and service resolution mechanisms are currently in place for different network protocols. In Windows Sockets 2, the protocol-independent name resolution APIs allow client and server applications to resolve these service and host names in a protocol-independent fashion. The new APIs in this category provide capabilities for services to be registered within a name space, and give a client the ability to find a particular service within the name spaces available to it.

Concurrent access to multiple network transports. Unlike version 1.1, which focused entirely on TCP/IP, the new API is transport-independent. Developers can access any network transport that has been plugged into the Windows Sockets 2 subsystem. The interface definition provides a homogeneous and comprehensive set of APIs for programming to multiple network transports concurrently. To enable esoteric, transport-specific features to be accessed though Windows Sockets, the Windows Sockets 2 Transport Protocol-specific Annex provides small sections that cover transport-specific details. TCP/IP, IPX/SPX, DECnet, and OSI are already included within Windows Sockets 2.

This facility means that developers no longer have to code a separate module for multiple transport interfaces. Instead, developers can now create and maintain a single Windows Sockets 2-based interface module in their networked Windows-based application software.

Quality of Service (QoS). Windows Sockets 2 provides access to QoS capabilities in new network media such as ATM and ISDN. Multimedia application developers can now request specific transfer rates and details of latency characteristics, and can responsively set up and tear down connections based on the throughput characteristics of the underlying network. In the wireless arena, applications can be notified when the network has become temporarily unavailable—for example, when an interface has lost contact with its base station.

Multipoint/multicast. Also new in version 2 is protocol-independent multipoint/multicast support. Applications can now use the multipoint communication method supported by a given protocol and join a multipoint group.

Stepping stones

The new specification has been designed to incorporate a series of straightforward transitional steps to its new functionality. Creating a Windows Sockets version 2 application does not require substantial effort.

The following is a suggested transition path.

Step 1. Verify the binary compatibility of your existing 16-bit and/or 32-bit Windows Sockets version 1.1 application with the new subsystem. Test it.

Step 2. Bypass the version 1.1 compatibility DLLs by relinking directly to the Windows Sockets version 2 DLL, WS2-32.DLL. Test it.

Step 3. Speed up your application by exploiting the new 32-bit performance functionality.

Step 4. Identify additional new areas that add value to or simplify your software and its architecture. Look at:

• Supporting multiple transports.

• QoS capabilities, especially if you're a multimedia software developer.

• New architectural possibilities in your code based on, for example, socket sharing capabilities.

Availability timeline

The following schedule for the availability of Windows Sockets 2 is subject to change:

December 1995

Intel and Microsoft release beta of Windows Sockets version 2 for Windows NT and Windows 95 SDK.

January through March 1996

Interoperability "bake-offs." Developers of Windows Sockets version 2 service providers and applications get together to test, debug, and optimize the interoperability of preliminary software.

April 1996

Final Windows Sockets version 2 specifications published.

May 1996 onward

Commercial Windows Sockets version 2 service providers and applications released.

Further information

The provisional specifications were published in May 1995. These documents and related information are available from the following Internet locations:

Mailing lists: To participate in the Windows Sockets Group, send e-mail to majordomo@mailbag.intel.com with "subscribe winsock-2" in the body of your e-mail.

Developer newsgroups: alt.winsock.programming; comp.os.ms-windows.programmer.tools.winsock.

FTP sites: ftp://ftp.stardust.com/pub/winsock/ for WinSock version 1.1 and version 2 documents, sample code, developer components;
ftp://www.intel.com/IAL/winsock2/ for WinSock version 2 information.

Web sites: http://www.stardust.com (Stardust Technologies WinSock Resource Center);
http://www.intel.com/IAL/winsock2/ (WinSock version 2 information);
http://www.microsoft.com/pages/developer/winsock/ (WinSock information).

Martin Hall is chairman of the Windows Sockets Group. He is also cofounder and chief technology officer of Stardust WinSock Labs in Campbell, California. He can be reached at martinh@stardust.com.


The Human Factor: Sizing Things Up

Tandy Trower

November 1, 1995

I received a recent inquiry asking for some clarification on the recommendations in The Windows Interface Guidelines for Software Design regarding the sizes and spacing for controls and how to convert these measurements into pixels. The guide uses the term "dialog base units" as the measure. It also suggests using the GetDialogBaseUnits function to determine the current system settings for this measure.

Dialog base units or dialog units?

As it turns out, this information is not quite correct. First, although the number of units called out in the guide is correct, the unit of measure is incorrect. The recommended measurements should have been given as "dialog units," not "dialog base units." Vertical and horizontal dialog base units are equal to the character height and average character width in pixels, respectively. Each vertical dialog base unit is actually eight vertical dialog units. A horizontal dialog base unit equals four horizontal dialog units.

For example, buttons, text boxes, and drop-down controls should be 14 dialog units high with a minimum of 4 dialog units between them and 7 dialog units of space from the edge of the window, as shown in the figure.

Recommended layout and spacing for controls

The second problem is that GetDialogBaseUnits will get you the metrics of the font named "System" rather than the font typically used in a Windows 95 dialog box. Instead, for Windows 95, you'll want to use SystemParametersInfo to get the NONCLIENTMETRICS structure to determine the normal font used for dialog text (IfMessageFont) and then use GetTextMetrics on that to get the font information.

Converting to pixels

Now that you have the correct font metrics, you can convert from dialog units to pixels using the calculation defined in the GetDialogBaseUnits function description (where X is width and Y is height):

X pixels = (X dialog units * X dialog base units) / 4

Y pixels = (Y dialog units * Y dialog base units) / 8

For example, the recommended height of command buttons is 14 dialog units. The vertical dialog base unit, based upon the height of the default MS Sans Serif font, is 13.

So, Y pixels = (14 * 13) / 8

Rounding to the nearest whole number means that most command buttons should end up being 23 pixels in height. (Note that the recommended heights for toolbar buttons differ slightly at 22 pixels for 16 x 16 pixel images and 30 pixels for 24 x 24 pixel images.)

If you want to know the dialog unit equivalent for something you've measured in pixels, use the following formulas:

X dialog units = (X pixels * 4) / X dialog base units

Y dialog units = (Y pixels * 8) / Y dialog base units

Recommended width

Another question is whether there is a recommendation for the width of controls. The guide doesn't include any information here, except for toolbar buttons (24 pixels and 32 pixels). The reason is that the width of controls such as text boxes, command buttons, and drop-down lists is mainly dependent on the content of the controls and their orientation to other controls. Generally, a command button should be wide enough to show its full label. (If you can't, use a ToolTip that provides the full label.) In Windows 95, the minimum button width used is 50 dialog units.

However, you should also consider the context of the buttons. For example, if you stack buttons in the upper right corner, it is usually best to make all the buttons the same width, provided that the lengths of the labels are all about the same. If the label for one of the buttons is substantially longer than the rest, you can make that button longer, but give the others the same shorter length. In other words, for buttons that appear together as a set, keep to a uniform width rather than depending solely on the label length.

Similar recommendations can be applied to text boxes or drop-down list controls. The control should be wide enough to display a typical entry, but also consider the alignment and relationship it has with other controls.

Tandy Trower is the director of UI design at Microsoft. After the Windows 95 event, he has been hoping to be invited to write guidelines for "The Tonight Show," but Jay doesn't return his calls.


MFC 4.0 Helps You Contain Your OLE Controls

Dale Rogerson

November 1, 1995

Do you have OLE Controls running around your system with no apps to contain them? Have you been trying to contain your OLE Controls on your own? Never fear, pardner. Microsoft Foundation Class Library (MFC) has spent the year in training, and the newly released version 4.0, included with Visual C++ version 4.0, now has the code needed to contain even the toughest OLE Control. (See "MFC 4.0: The Story Can Be Told" in this issue of Developer Network News).

Whether you are putting OLE Controls on dialog boxes, form views, or plain old windows, the OLE Control container support added to MFC 4.0, ClassWizard, and AppWizard will make using OLE Controls much easier.

Component Gallery

AppWizard has been expanded to generate OLE Control containers; all you need to do is mark the appropriate check box. If you don't check the box when you run AppWizard, then follow the steps in the "OLE Control Containers: Manually Enabling OLE Control Containment" topic in the integrated Books Online to add the container support.

After AppWizard creates the OLE Control container, it's time to add OLE Controls to the application. From the Insert menu in Developer Studio, select the Component menu item. This starts the Component Gallery (see the figure above), a new tool that simplifies and promotes code reuse. The Component Gallery is a repository for program components such as OLE Controls and C++ classes.

To insert an OLE Control into your application, switch to the OLE Controls tab in Component Gallery. Select the control and click the Insert button. Component Gallery automatically generates a class to wrap the IDispatch interface of the OLE Control. Below is part of the generated header file for the OLE Control grid.

#ifndef __GRIDCTRL_H__

#define __GRIDCTRL_H__

// Machine generated IDispatch wrapper class(es) created by

// Microsoft Visual C++.

// NOTE: Do not modify the contents of this file. If this class is

// regenerated by Microsoft Visual C++, your modifications will be overwritten.

// Dispatch interfaces referenced by this interface.

class CPicture;

class COleFont;

/////////////////////////////////////////////////////////////////////////////

// CGridCtrl wrapper class

class CGridCtrl : public CWnd

{

protected:

DECLARE_DYNCREATE(CGridCtrl)

public:

CLSID const& GetClsid()

{

static CLSID const clsid

= { 0xa8c3b720, 0xb5a, 0x101b,

{ 0xb2, 0x2e, 0x0, 0xaa, 0x0, 0x37,

0xb2, 0xfc } };

return clsid;

}

BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect,

CWnd* pParentWnd, UINT nID, CFile* pPersist = NULL, BOOL bStorage = FALSE,

BSTR bstrLicKey = NULL)

{ return CreateControl( GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd,

nID, pPersist, bStorage, bstrLicKey); }

// Attributes.

public:

CString Get_Text();

void Set_Text(LPCTSTR);

CString GetText();

void SetText(LPCTSTR);

CString GetFontName();

void SetFontName(LPCTSTR);

float GetFontSize();

void SetFontSize(float);

.

.

.

To use this control in a CView-derived class, add the following lines to the OnInitialUpdate function:

// Get size of client area.

CRect rectClient ;

GetClientRect(&rectClient) ;

rectClient.InflateRect(1,1) ;

// Create control.

m_aGrid.Create( "Grid",

WS_VISIBLE,

rectClient,

this,

IDC_GRID) ;

// Set dimensions.

m_aGrid.SetRows(10) ;

m_aGrid.SetCols(10) ;

// Set Row 1 Col 4 to "Hello!"

m_aGrid.SetRow(1) ;

m_aGrid.SetCol(4) ;

m_aGrid.SetText("Hello!");

The application now has a working OLE Control!

Dialog boxes

Dialog boxes and form views also support OLE Controls. Using Component Gallery to insert the control into a project adds the control to the Tools toolbar. The dialog editor fully supports OLE Controls. Properties can be viewed and changed, and the OLE Controls can also be tested.

Events

Handling events in dialog boxes and CFormView-derived classes is easy; ClassWizard does all the work. MFC 4.0 supports OLE Control events by using event maps that are similar in concept to message maps. The "OLE Control Containers: Handling Events from an OLE Control" article in Books Online explains how to add events to a CDialog-derived class. The process is very similar to handling a menu command: Select the ID of the OLE Control, then select the events you want to handle. Following is the code ClassWizard generates.

class CGridDlg : public CDialog

{

.

.

.

// Dialog Data.

//{{AFX_DATA(CGridDlg)

enum { IDD = IDD_GRIDDLG };

CGridCtrl m_Grid;

//}}AFX_DATA

.

.

.

// Implementation.

protected:

// Generated message map functions.

//{{AFX_MSG(CGridDlg)

afx_msg void OnMouseDownGrid(short Button, short Shift, long X, long Y);

afx_msg void OnSelChangeGrid();

DECLARE_EVENTSINK_MAP()

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

ClassWizard puts the following event map implementation into the .CPP file.

BEGIN_EVENTSINK_MAP(CGridDlg, CDialog)

//{{AFX_EVENTSINK_MAP(CGridDlg)

ON_EVENT(CGridDlg, IDC_GRID,

-605 /* MouseDown */,

OnMouseDownGrid,

VTS_I2 VTS_I2 VTS_I4 VTS_I4)

ON_EVENT(CGridDlg, IDC_GRID,

2 /* SelChange */,

OnSelChangeGrid, VTS_NONE)

//}}AFX_EVENTSINK_MAP

END_EVENTSINK_MAP()

Handling OLE Controls in other CCmdTarget-derived classes, such as CWnd and CView, isn't as easy as in CDialog- or CFormView-derived classes. ClassWizard needs a resource ID for an OLE Control in order to support handling events for the control. CDialog and CFormView classes, on the other hand, are both associated with dialog template resources that contain the IDs for the OLE Controls. Other CCmdTarget-derived classes are not associated with resources, so ClassWizard cannot work its magic.

Hope is not completely lost. It is still possible to use ClassWizard to generate the event map entries. One way is to associate your CCmdTarget-derived class with a dialog template resource. First, create a new dialog box. Put the OLE Control on the dialog box. With the dialog editor active, start ClassWizard. ClassWizard asks if you want to create a new class, import a class, or select an existing class. You want to select an existing class, so select the last radio button. ClassWizard will then prompt you for one of the classes in your application. Select the CView or CWnd class that you want to contain the OLE Control. Answer 'yes' to ClassWizard's request for confirmation. Change to the Message Map tab on the ClassWizard dialog box. Select the ID for your OLE Control and start adding event handlers to your application.

Another method for using ClassWizard to add events to CWnd and CView classes is to use a dummy CDialog-derived class. First, create a dialog box with the OLE Control on it. Then, create a dialog class for this dialog box. Use ClassWizard to add event handlers to the dialog class. Copy the event handlers to your CWnd- or CView-derived class.

Dale Rogerson is madly pumping iron, learning how to swim, and trying on new swimsuits so he can get a part on "Baywatch," or at least be able to answer letters on the "Baywatch" home page.


MFC 4.0: The Story Can Be Told

New version adds control views and OLE container/control support

Sal Coco

November 1, 1995

One of the most significant products available for Windows-based software development is the Microsoft Foundation Class Library (MFC) version 4.0. MFC 4.0 fully supports 32-bit programming for Microsoft Windows 95. Your MFC applications will run on Windows 95, Windows NT 3.51, or Win32s 1.3. Applications developed with MFC 4.0 will automatically have the visual look and feel appropriate for any of these operating systems.

Using Visual C++ 4.0 and MFC 4.0 simplifies the task of meeting the Windows 95 logo requirements. Of course, it is virtually impossible for a development tool to automatically satisfy all of the logo requirements, since a lot depends on what your application is doing. However, using Visual C++ 4.0 and MFC 4.0 allows you to satisfy some of the requirements automatically, including the stipulation for providing a Win32 executable in a portable executable (PE) format, Windows NT compatibility, and long file name support.

New Win32 common control classes

Windows 95 common controls are now available in Windows NT 3.51 and Win32s 1.3. MFC 4.0 offers new common control classes that encapsulate the following controls: rich text edit, slider, list, tree, spin button, header, progress, hot key, tool tip, tab, animate, tool bar, status bar, image list, drag list box, and check list box. The new common control classes are as easy to use as familiar standard control classes such as CEdit.

MFC 4.0 has a new view control base class, CCtrlView, that allows you to create a view from one of the new common control classes with little effort. Although previously it was technically possible to attach a control class to a CView object, CCtrlView hammers out all the details of making your own control view. CCtrlView can also be used with third-party controls and with controls you design yourself.

MFC 4.0 exploits the new CCtrlView class by introducing several new common control view classes: CListView, CTreeView, and CRichEditView.

Use a common control class when you need a plain child window control; for example, in a dialog box or form view. Plain common control classes are especially useful in the same window with other child control windows, as in a typical dialog box.

Use a common control view when you want the control to behave as a view window, such as in document/view architecture. A control view will occupy the entire client area of a single splitter window pane or frame window, and will automatically resize itself when the parent window is resized. In addition, command messages from menus, accelerator keys, and toolbars will be routed to the view automatically. Of course, the user of these control views can override most of the default functionality and customize the behavior as needed.

A simple example

To illustrate the power of these common control classes and control views, let's use them to build a simple application that allows a user to preview animation files. To make this application user-friendly, let's add a splitter window with two vertical panes: one that displays a list of animation file names (organized into several categories), and one that plays the animation.

The application will behave similarly to the Windows 95 Explorer. A tree view is used in the left pane and an animation view is used in the right pane of the vertical splitter window. The user will select an animation file by drilling down into the tree view user interface and finding its file name. Once the animation file is selected, the application will play it in the right pane of the splitter window.

One approach to implementing this simple application is to have AppWizard generate the code for a basic application, using the CView class. After the application is built, we can edit the code and add a splitter window using the CSplitterWnd class. After creating the individual panes of the splitter window, we just need to add the appropriate view classes. Since the tree view is already implemented, we can use CTreeView. At this time, MFC does not contain an animation view class, so we have to create one ourselves using the CCtrlView base class. A brief example of the code needed to declare a CAnimateView class is shown below. This code is by no means complete; its purpose is to illustrate the basic idea of creating your own view control object.

Here's the CAnimateView header file:

// CAnimateView header file

class CAnimateView : public CCtrlView

{

DECLARE_DYNCREATE(CAnimateView)

public:

// CAnimateView constructor

CAnimateView();

// CAnimateView destructor

~CAnimateView();

// Returns a reference to the animation

// control.

CAnimateCtrl& GetAnimateCtrl() const;

// Perform control initialization.

virtual BOOL PreCreateWindow(CREATESTRUCT&

cs);

// Open the animation file.

void OnInitialUpdate();

//{{AFX_MSG(CAnimateView)

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

As you can see, creating a custom control view class based on the CCtrlView class is an easy and straightforward task.

// CAnimateView source file

IMPLEMENT_DYNCREATE(CAnimateView, CCtrlView)

BEGIN_MESSAGE_MAP(CAnimateView, CCtrlView)

//{{AFX_MSG_MAP(CAnimateView)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

// CAnimateView constructor.

// This is where CCtrlView uses the control

// class name "SysAnimate32" to create the

// view object.

CAnimateView::CAnimateView() : CCtrlView("SysAnimate32", AFX_WS_DEFAULT_VIEW)

{ }

// Destructor.

CAnimateView::~CAnimateView()

{ }

// Code used to return the reference of the CAnimateCtrl.

CAnimateCtrl& CAnimateView::GetAnimateCtrl() const

{ return *(CAnimateCtrl*)this; }

// Called by the framework before the creation

// of the window attached to this CWnd object.

BOOL

CAnimateView::PreCreateWindow(CREATESTRUCT& cs)

{

static BOOL bInit = FALSE;

// Initialize the common controls once.

if ( bInit == FALSE )

{

// The InitCommonControls function ensures

// that the common control DLL is loaded.

InitCommonControls();

bInit = TRUE;

}

return CCtrlView::PreCreateWindow(cs);

}

// Write your initialization code here.

void CAnimateView::OnInitialUpdate(void)

{

CCtrlView::OnInitialUpdate();

// Open an animation AVI file for the animation control.

GetAnimateCtrl().Open("c:\\myavi.avi");

}

Now that we have the animation control view object and the tree view object, we can use these two views when we create the panes for the splitter window. And presto, we have an application.

New common dialogs

MFC 4.0 also introduces two common dialog classes—CPageSetupDialog and COlePropertiesDialog—that encapsulate the common dialog boxes in Windows. These provide easy-to-use implementations of complicated dialog boxes. MFC 4.0 also adds new functionality to the CFileDialog class.

The services provided by the Windows common OLE Page Setup dialog box are now encapsulated by the CPageSetupDialog class, which also provides support for setting and modifying print margins. The CPageSetupDialog class is derived from CCommonDialog and replaces the Print Setup dialog box. The Windows common OLE Object Properties dialog box is now encapsulated by the COlePropertiesDialog class. This dialog box provides a way to display and modify the properties of an OLE document item in a manner consistent with the Windows standards.

The old CFileDialog class also has new member functions for customizing the File Open dialog box, allowing you to add your own controls.

OLE container and control support

The introduction of the OLE Control Development Kit (CDK) provided the tools necessary to develop OLE Controls. Today the CDK has disappeared, and all of its components and classes have been integrated into MFC 4.0, which now offers OLE Control container and OLE Control implementation support. AppWizard now allows developers to add OLE Control support to their applications automatically, without writing code. (See companion story "MFC 4.0 Helps You Contain Your OLE Controls" in this issue of Developer Network News).

The new OLE Control container makes it easy to add OLE Controls to any window, similar to adding a standard Windows control. A developer who uses an OLE Control container does not need to know all the tedious implementation details of an OLE container application, only that the OLE Control container support is based on the CWnd class. An OLE Control becomes a unique kind of child window, inheriting new OLE functionality from the CWnd class, including a new method, CWnd::CreateControl. This method allows the dynamic creation of an OLE Control instead of an ordinary window.

AppWizard has become smarter with the introduction of a visual approach to adding OLE Control support. Use AppWizard to turn on the support for OLE Controls. OLE Control support is provided for dialog box-based or window-based applications. AppWizard will generate the code necessary to set up and prepare the OLE Control container. Your AppWizard-generated application is now ready to use OLE Controls.

New Data Access Object classes

The Data Access Object (DAO) classes allow you to set up and use workspaces, and to create and manipulate tables, queries, and indexes for tables using the SQL Data Definition Language (DDL). DAOs allow direct access to the Jet database engine, which is also used in the Microsoft Access and Microsoft Visual Basic 4.0 development environments. Overall data access performance improves when using the DAO classes with the Jet database engine. The Jet database engine is used when manipulating Microsoft Access databases.

The DAO classes allow you to connect to open database connectivity (ODBC) data sources. This allows you to connect to tables stored on SQL Server, Oracle, or other databases.

Multithreaded synchronization classes

MFC 4.0 includes several multithreaded classes, which provide synchronization methods to ensure the integrity of a resource and to gain access to the protected resource. These synchronization classes have been organized into two categories: synchronization object classes and synchronization access object classes.

The synchronization object classes control access to a resource and ensure its integrity. Classes in this category are CSyncObject and its derived classes CEvent, CSemaphore, CMutex, and CCriticalSection.

The synchronization access object classes allow the application to gain access to resources controlled by the synchronization object classes. These methods are CSingleLock and CMultiLock. Use CSingleLock when your application accesses a single controlled resource; use CMultiLock when your application accesses multiple controlled resources.

How to get MFC 4.0

MFC 4.0 can be purchased with Visual C++ 4.0. Visual C++ subscriptions, which provide three releases per year, are now available in the United States, Canada, and Europe. Elsewhere, contact your local Microsoft subsidiary. MFC 4.0 is also available from licensed software vendors.

Sal Coco is a strategic account engineer in the Premier Developer Support division of Microsoft Product Support Services.


Tapping into TAPI

Nancy Winnick Cluts

September 22, 1995

The Microsoft Windows Telephony Application Programming Interface (TAPI) provides a way for applications to support telephone communication. TAPI is vitally important for developers who want to jump on that band wagon (which is groaning under all of the weight) and move their applications online.

The following is a brief overview of TAPI, including how applications interact with TAPI, some telephony basics, and where to find information and tools to help create telephony apps.

What is TAPI?

TAPI is used to communicate via telephones. Among the abilities that TAPI facilitates are:

• Connecting directly to a telephone network.

• Automatic phone dialing.

• Transmission of data (files, faxes, electronic mail).

• Access to data (news, information services).

• Conference calling.

• Voice mail.

• Caller identification.

• Control of a remote computer.

• Collaborative computing over telephone lines.

Windows 95 comes with a telephony application, DIALER.EXE, that can dial voice calls, act as a proxy for applications making simple telephony requests, and maintain a call log. Figure 1 shows the main screen for the phone dialer application.

Figure 1. The DIALER.EXE application

If you play with the DIALER application, you'll see some of the things that an application can do to give a user the ability to dial calls, set dialing properties, do speed dialing, and set up a connection. A user sets the dialing properties in the DIALER application by using the dialog box shown below.

Figure 2. The dialing properties dialog box

TAPI operates independently of the underlying telephone network and equipment. An application that uses T API doesn't have to worry about which kind of equipment it is hooked up to—it just needs to interact with the API itself. The following figure shows the relationship among the application, TAPI, and the telephony service provider.

Figure 3. TAPI and applications

As Figure 3 shows, the application interacts with the telephony dynamic-link library (DLL) via TAPI. The telephony DLL is part of the Windows operating system and implements TAPI support. The telephony DLL interacts with service providers via the Telephony Service Provider Interface (TSPI). Service providers can be thought of as akin to printer drivers; they are written by telephony hardware vendors to support operating within Windows.

Some technical issues

To avoid some pitfalls when you develop an application that includes TAPI functionality, there are a couple of things you must understand about how TAPI works. These are lower-level than what is covered above.

When an application supports TAPI, it must first initialize TAPI via the lineInitialize function. When your app makes this call, the telephony DLL creates a hidden window on behalf of your application. This hidden window is used as a method to send notifications and messages. These messages are posted to the hidden window for the different asynchronous events, completion notifications, and state messages (whether the line is connected, proceeding, dialing, and so on). If your application is multithreaded, you need to ensure that the thread that made the call to lineInitialize has a message loop and that the thread services this message loop. If the thread does not service the message loop or if it doesn't have a message loop, your application won't get the notifications meant for it. To put it a little more harshly, your application won't work.

When you make calls into TAPI that require a structure to be filled in, you will need to check the amount of space needed for the structure and re-allocate memory until you have a memory block that is large enough to hold the structure. The reason for this is that each service provider, much like a printer driver, supports different capabilities and holds different amounts of information. As a result, if you pass a pointer to a structure that is not large enough and you don't check to be sure that you have allocated enough space (by checking the dwNeededSize versus dwTotalSize members of the structure that is returned), the structure will be filled in with zeros and your application won't work.

Documentation and development tools

The Win32 Software Development Kit (SDK) contains documentation, tools, and sample code to help you learn about TAPI. Two documents, the Microsoft Telephony Programmer's Reference and the Microsoft Telephony Service Provider Interface (TSPI) for Telephony, are provided to give you some reference material and development guidance. The programmer's reference is intended to document the functionality that an application using TAPI will need. The service provider documentation is for developers who are going to write their own TAPI services (that is, vendors of telephony equipment).

There are also some tools that come with the Win32 SDK to help developers understand TAPI and incorporate TAPI functionality into an application. TB14.EXE is a 32-bit telephony browser that allows you to play around with the different TAPI calls and your COM ports. You will be able to test whether your COM port and modem are set up correctly to begin with (if they aren't, you'll be wasting a lot of time and pulling out your hair trying to figure out why your application doesn't work). It also allows you to see how the different TAPI structures are filled in. This will help you see whether your application is calling the different TAPI functions correctly. The figure below shows the main screen displayed by TB14.EXE.

Figure 4. The TAPI browser: TB14.EXE

Another tool that you can use is the service provider tool, ESPEXE.EXE. This tool is a TAPI service provider that supports multiple virtual line and phone devices. You can configure it for your application. It doesn't require any special hardware, and it supports the entire Telephony Service Provider Interface (including the Windows 95 TAPI extensions). You can use this tool in both Windows 3.1 with TAPI 1.0 and in Windows 95 with TAPI 1.1.

The TAPICOMM sample

Tucked away in the Win32 SDK sample tree, you will find the TAPICOMM sample. This sample demonstrates how to do data transmission over a telephone.

If you take a look at the source code for this sample, you can learn how to implement basic telephony functions such as initializing TAPI: opening a phone line, gathering line device capabilities, transmitting data via the COMM (Communications) API, closing a line, and shutting down TAPI.

If you would like more detailed information, take a look at some of the references listed in the bibliography or read my next article, "Creating a TAPI Connection Using CTapiConnection," which is scheduled for the January release of the Microsoft Development Library. The article describes the details of implementing basic TAPI functionality using CTapiConnection, a Microsoft Foundation Class Library (MFC)-based class that I created.

For Further Reading

"Developing Applications Using the Windows Telephony API," Toby Nixon, MSDN Conferences/Tech*Ed 1994/Microsoft At Work.
Microsoft Telephony Programmer's Reference, Win32 SDK.
Microsoft Telephony Service Provider Interface (TSPI) for Telephony, Win32 SDK.

Nancy Winnick Cluts is a writer for the Microsoft Developer Network. When not trying to further her book-writing career through shameless self-promotion—Programming the Windows 95 User Interface (Microsoft Press, August 1995)—she can be found in her rose garden attempting to eradicate black spot and aphids by chanting.


TrueType Open Extends Support for International Typography

New features include glyph substitution and positioning

Nadine Kano

November 1, 1995

TrueType Open extends the TrueType font file format to provide advanced support for international typography. TrueType Open is particularly useful for non-Latin languages such as Arabic (which requires glyph shaping) or Japanese and Chinese (which require horizontal and vertical glyph alternates). The TrueType Open Font Specification (version 1.0) describes the TrueType Open file format in detail and is included in the October 1995 edition of the Microsoft Development Library. Font providers who intend to support non-Latin or multilingual fonts should study this spec, and application developers can also benefit from it. Applications that understand the file format can retrieve information necessary for handling complex glyph substitution and displaying multilingual text. In the future, Microsoft will provide a TrueType Open API that will assist text-processing applications in implementing the features of TrueType Open fonts. For now, developers can write their own code to handle TrueType Open fonts.

The evolution of TrueType in Windows

TrueType fonts were introduced to the Microsoft Windows environment with Windows version 3.1. Previously, Windows used only raster and vector fonts, which often resulted in poorly spaced text and glyphs with unattractive, jagged edges. TrueType fonts define a "scalable outline" for each glyph and "hints" that improve font appearance at any resolution. Therefore, TrueType fonts look better and are more legible than raster or vector fonts when displayed or printed in any point size. Also, because Windows generates bitmaps based on a single outline for each glyph, TrueType fonts are easier to create and to manipulate. Font vendors don't have to predefine an entire set of bitmaps to represent a font at each potential point size.

TrueType and Windows 95

Windows 95 introduced improvements to the TrueType font technology. For example, the 32-bit rasterizer in Windows 95 provides faster and better hinting and rendering. It also supports "font smoothing"—a method of smoothing bitmap edges using shades of gray. Some TrueType 95 features are particularly useful for languages such as Japanese. For example, the TrueType format now describes metrics that assist with vertical text layout. TrueType fonts also support the addition of embedded bitmaps. Japanese Windows 95, for example, uses embedded bitmaps to render Kanji characters in very small sizes. For a comprehensive description of TrueType and how fonts are implemented in Windows, see "TrueType and Microsoft Windows Version 3.1" and "TrueType in Windows 95" in the Microsoft Development Library.

TrueType fonts in Windows 3.1 supported only five "charset" tags for fonts: ANSI_CHARSET, OEM_CHARSET, SYMBOL_CHARSET, SHIFTJIS_CHARSET, and DEFAULT_CHARSET. The TrueType font format now describes the code pages (out of a possible 36) and the Unicode subranges (out of about 70) that a particular font supports. The TrueType spec lists these code pages and Unicode subranges.

Although Windows 95 and Windows NT are based on different character encodings (see "Yes, Virginia, Windows 95 Does Do Unicode" by Nadine Kano, Developer Network News, July/August 1995), the TrueType font format, which is supported on both operating systems, is the same worldwide. In fact, most TrueType fonts in the Windows environment already use the Unicode encoding internally. Thus, TrueType is ready to move with Microsoft operating systems toward full Unicode support.

What TrueType Open can do

TrueType Open builds on the Unicode character encoding standard to support additional operations for proper rendering and visual arrangement of those characters. TrueType Open supports the following features:

Glyph substitution. Previously, fonts were limited to a 1:1 mapping between a code point in a code page and a glyph in a font table. TrueType Open allows a richer mapping between character codes and glyphs. For example, a single character in Arabic can have up to four different shapes, depending on whether it stands alone or appears at the beginning, middle, or end of a word. Glyph substitution can also be used to substitute vertical glyphs for horizontal glyphs, to substitute ligatures for multiple glyphs (œ for oe), and to support glyph variants such as swash capitals.

Glyph positioning. TrueType Open uses three types of glyph positioning information: Basic glyph positioning information is used to position individual glyphs such as superscripts, accent marks, and glyphs in kerning pairs; baseline information is used to adjust the baselines of different scripts on the same line of text; and justification information covers positioning information needed for text justification (for example, determining how much interword spacing should be added to the line before intercharacter spacing needs to be changed).

Script and language information. Font vendors may choose to provide font information that is script-specific or language-specific. For example, vendors may wish to distinguish between Chinese and Japanese fonts. Although Chinese and Japanese ideographs are in the same Unicode subrange, Japanese glyphs and Chinese glyphs for the same character may differ slightly in shape. Also, some characters are used differently in different languages; for example, s+s often forms b in German, but this never happens in English, although both languages use the Latin script.

Availability

The Middle East and Far East editions of Windows 95 ship fonts containing TrueType Open information, and the system makes use of TrueType Open features such as glyph substitution for Arabic and vertical glyph substitution for Japanese. Applications that wish to process additional TrueType Open features can pass Windows 95 a string represented by glyph indexes (indexes into font tables) by calling ExtTextOutA and setting the ETO_GLYPH_INDEX flag. Future versions of Windows NT will also make use of TrueType Open.

TrueType Open is labeled "open" because its format is straightforward and easy to parse. Vendors can add features as long as they adhere to the format. The specification defines table formats carefully so that applications can access font information directly without having to call an API. A TrueType Open API that will provide standard services is also in the works and is scheduled for release in the first half of 1996.

Nadine Kano ponders the deeper questions of life while blasting opera (mostly Puccini) from her stereo. She can be reached at the Internet address global@microsoft.com.


Use Visual Basic 4.0 to Distribute the Load with Remote Automation

Visual Basic 4.0 and OLE 2.0 now provide the tools to build distributed solutions

Robert Eineigl and Randy Morgan

November 1, 1995

Previously in Developer Network News, we gave a taste of the increased power of Visual Basic 4.0. Specifically, we covered the new features in Visual Basic 4.0 and built a simple remote automation server. (See "Visual Basic 4.0 Goes Live: 16-Bit/32-Bit Rapid Application Development," Developer Network News, Sept/Oct 1995.)

In this article, we'll go into greater depth by building a skeletal distributed processing system that allows clients to pass processing tasks to remote nodes branched off a central pool manager. This architecture extends the application server model to allow clients located anywhere on the network to call OLE servers by means of a central pool manager.

Three-tiered distributed client/server architecture

The promise of distributed processing has tantalized developers since the proliferation of networked personal computers began. A system where components of a business system do not reside either exclusively on a central big-iron computer or on every user's computer, but instead are managed from nodes throughout the network, carries many advantages. These include better disk space utilization, ease of maintenance, increased processing power, granular management of business policies, and the ability to balance processing loads.

But until now, developers interested in distributed solutions either had to write their own customized solutions—reinventing the wheel many times over—or were forced to wait for operating systems to evolve to the point of providing the enabling infrastructure to allow more general, portable solutions.

Visual Basic 4.0 and OLE 2.0 now provide the tools to build distributed solutions for Windows-based platforms. Additionally, because OLE 2.0 serves as the technology springboard for Microsoft's future Windows NT distributed operating system (code-named "Cairo"), the solutions developed today should migrate smoothly to Cairo.

Distributed architecture

Once the dependency on a central mainframe or on single-tier client/server architecture is removed, the possible topologies for distributed systems are practically infinite.

In our example, we chose a three-tier topology where the clients, connecting through a central server, obtain services from satellite servers called from the central server. We created a simplified pool manager that runs on the central server, accepts requests from clients for object handles, and, in turn, requests object handles from a third-tier satellite or local object manager.

The system design

In our example, we built three main pieces to provide the basic structure and an additional OLE server to perform the distributed processing task. The three main pieces are the client, a central pool manager (ObjectPoolMgr), and the satellite (or local) object manager (CreateObjectLocalMgr). The satellite object manager is configured to launch a specified number of objects when it first runs, thereby taking the overhead hit up front and removing a later bottleneck to system response. This pool of objects is managed locally, so the central pool manager is unaware of those details. At the client's request, the satellite object manager instantiates either a Visual Basic 4.0 OLE server object or a Microsoft Excel workbook object locally to perform the processing.

The sequence of events is as follows: The client requests a service from the central pool manager. The central pool manager then requests an object managed by the satellite object manager. The satellite object manager passes the object handle back to the client, transparently by means of the central pool manager, and the client calls a method of the object to perform the processing. At the conclusion of the processing, the client frees the object handle for reuse by another client.

The example

Due to the limited scope of this column, we opted to write a streamlined, simplified central pool manager and satellite object manager, along with an elementary client. The client asks for a loan payment calculation—a simple calculation that doesn't require farming out to another processor but is included as a placeholder for testing a more extensive algorithm.

We concentrated on providing a comprehensible example of the essential mechanics that you can build upon to create a more realistic and useful system. The full code for this three-tier system exceeds our space limitations in this column, but can be found by going to the online version of this article at http://www.microsoft.com/devnews and downloading the sample code file.

The client

Since OLE handles the thunking between 16-bit and 32-bit clients and servers, the client application could be either 16-bit or 32-bit. The servers created with Visual Basic 4.0 can be only 32-bit. Windows 95 and Windows NT can each be either clients or servers. The remote automation code in the client gets a handle to the central pool manager, which provides class functions to pass handles to satellite object servers back to the client for use.

Dim objExcel As Object, objFinCalc As Object,

objFinCalcDLL As

Object, objCreateMgr As Object

Dim cResults As Currency, nRet As Long

Set objCreateMgr = _

CreateObject("ObjectPoolMgr.ObjectMgr")

objCreateMgr.SetObjectLocalMgr

' For illustrative purposes only.

' If Excel is not installed on satellite

' computer, comment out following lines.

nRet = objCreateMgr.GetPoolObject _

(objExcel, "Excel")

' Place code to call native Excel function

' or load a workbook and call a custom macro.

If nRet = True Then

' Finished with objExcel object; call

' function in ObjectPoolMgr to release it.

objCreateMgr.ReleasePoolObject "Excel"

End If

nRet = objCreateMgr.GetPoolObject _

(objFinCalc, "FinCalc")

If nRet = True Then

' Call method in FinCalc object.

cResults = objFinCalc.Payment _

(Text1.Text, Text2.Text, Text3.Text, _

Text4.Text, Text5.Text)

' Display results.

Text6 = CStr(cResults)

' Finished with FinCalc object; call

' function in ObjectPoolMgr to release it.

objCreateMgr.ReleasePoolObject "FinCalc"

End If

' Call same function in an in-process DLL on

' central pool manager computer.

' DLL is loaded on demand (created multi-use)

' and unloaded when pool manager closes.

nRet = objCreateMgr.GetPoolObject _

(objFinCalcDLL, "FinCalcDLL")

If nRet = True Then

' Call method in FinCalcDLL DLL.

cResults = objFinCalcDLL.Payment _

(Text1.Text, Text2.Text, Text3.Text, _

Text4.Text, Text5.Text)

Text7 = CStr(cResults)

End If

Note that the function used to instantiate the remote objects is CreateObject, not GetObject. This is because of a limitation in Visual Basic 4.0, which is documented in the Help file (a note in the GetObject description states that you can't use GetObject to obtain a reference to a class created with Visual Basic). To make the code consistent, we used CreateObject throughout the example.

The central pool manager

The remote automation code in the pool manager (ObjectPoolMgr) is contained in three class functions: SetObjectLocalMgr, GetPoolObject, and ReleasePoolObject. The first function instantiates a specific satellite object manager called CreateObjectLocalMgr.

To increase the number of satellite servers in the third tier, you would have to make the class names (Visual Basic 4.0 project names) unique, perhaps by adopting a numeric scheme, for example, CreateObjectLocalMgr1, CreateObjectLocalMgr2, and so on.

The implementation of an algorithm to balance the load by time of day or demand is an exercise left to the reader. Visual Basic 4.0 comes with an extensive sample pool manager, located under \VB\SAMPLES\REMAUTO\POOLMNGR, that points the way. (This sample is also included in the October 1995 edition of the Microsoft Development Library, under Sample Code, Product Samples.)

Back to our simpler example. The following code obtains the handle to one specific instance of a satellite:

Public Sub SetObjectLocalMgr()

' Get handle to satellite object manager.

Set objCreateLocalMgr = CreateObject _

("CreateObjectLocalMgr.CreateObjectMgr")

End Sub

GetPoolObject and ReleasePoolObject call functions in the satellite object manager to obtain the object handles that belong to objects local to the satellite object manager. It is important to realize that the central pool manager has no need to know which objects are being handed back to the client, or even their locations. The Remote Automation Connection Manager (RACMan) does need to know network addresses when setting up the system, but the code does not care.

Public Function GetPoolObject(ObjPoolObject As

Object, sObjectRequested As String)

Dim nRet As Integer

nRet = False

' Call class functions in the satellite

' object manager, CreateObjectLocalMgr.

Select Case sObjectRequested

Case "Excel"

If objCreateLocalMgr.ExcelObjectAvailable _

= True Then

Set ObjPoolObject = _

objCreateLocalMgr.GetExcelObjectHandle

nRet = True

End If

Case "FinCalc"

If objCreateLocalMgr.FinCalcObjectAvailable _

= True Then

Set ObjPoolObject = _

objCreateLocalMgr.GetFinCalcObjectHandle

nRet = True

End If

Case "FinCalcDLL"

' Call local, in-process DLL, registered

' via REGSVR32.exe.

Set ObjPoolObject = _

CreateObject("FinancialCalcDLL.FinCalcDLL")

nRet = True

End Select

GetPoolObject = nRet

End Function

Public Sub ReleasePoolObject(sObjectRelease

As String)

Select Case sObjectRelease

' Calls functions in CreateObjectLocalMgr.

Case "Excel"

objCreateLocalMgr.FreeExcelObjectHandle

Case "FinCalc"

objCreateLocalMgr.FreeFinCalcObjectHandle

End Select

End Sub

The in-process DLL

To show the use of an in-process dynamic-link library (DLL), we chose to hang an OLE DLL directly off the central pool manager (ObjectPoolMgr). This DLL duplicates the loan processing code in the Visual Basic OLE server executable (the cross-process server) running on the third-tier computer. This exemplifies that the pool manager could choose to utilize its own processing time, if a load balancing algorithm finds spare cycles on the central pool manager computer. The DLL also allows us to compare in-process vs. out-of-process servers, and second-tier vs. third-tier performance.

The satellite object manager

In the third tier, we have the satellite object manager and the actual processing servers. The satellite object manager, CreateObjectLocalMgr, contains six class functions—that is, three functions for each of the two OLE objects: the Visual Basic 4.0 server (FinancialCalc.exe) and the Microsoft Excel 5.0 (or higher) executable, which can be accessed as an OLE server via OLE Automation calls. Two functions simply manage the array of object handles:

Public Function FinCalcObjectAvailable()

Public Sub FreeFinCalcObjectHandle()

The third function actually instantiates the objects, based on the array limits. The form load event for CreateObjectLocalMgr sets up a default pool size of one, for both the Microsoft Excel and Visual Basic 4.0 OLE server objects, and allows manual resetting of the pool size.

Public Function GetFinCalcObjectHandle() As

Object

'Checks to see if there are FinCalc Objects

'left.

If nFinCalcObjCount < UBound(objFinCalc)

Then

Set GetFinCalcObjectHandle = _

objFinCalc(nFinCalcObjCount)

nFinCalcObjCount = nFinCalcObjCount + 1

End If

End Function

The Visual Basic OLE server

The object of this exercise (pun intended) is to pass the handle of an OLE server that actually performs the distributed processing back to the client. Our object of desire is a bare-bones OLE server created by Visual Basic 4.0 (FinancialCalc), which has one class function, Payment, as a wrapper around the intrinsic function Pmt. The function header looks like this:

Public Function Payment(APR As Currency,

TotalPayments As Long, TotalAmount As Currency,

FutureValue As Currency, WhenDue

As Long) As Currency

Development tips

Now that the Visual Basic 4.0 Integrated Development Environment (IDE) is flagged as a multi-instance executable, you can debug the three tiers and the server by running multiple instances of the IDE, each loaded with a different layer. This will work, provided that you have not used RACMan to point the client to remote computers. If you have, just reset the addresses for the objects involved back to (NONE) and toggle the Register menu to Local.

When a watch expression is evaluated, the end result must be a text string that can be displayed in the watch window. For this reason, if you set a watch on an object variable pointing to an object created by Visual Basic 4.0, you will get the message "Object doesn't support this property or method." Visual Basic tries to evaluate the default property of the object to which the variable refers. For the Microsoft Excel application object, this is the Name property, which is a string.

If the default property of the object is a reference to another object, Visual Basic looks for the default property of that object. As long as the watch expression can be evaluated to a string, it can be displayed.

The problem with references to objects created from Visual Basic 4.0 class modules is that there is no way to designate one property or method of a class module as the default. Therefore, if you want to watch a variable that contains such an object reference, your watch expression should specify either the TypeName function or a property of the object:

TypeName(objTest) (or) objTest.Name

Setup

To simplify setup, we made the assumption that Visual Basic 4.0 Enterprise Edition is already installed on the three computers needed to test the example. For a real-world implementation, use the Setup Wizard to create setup images containing all the DLLs and OLE Controls needed to run the compiled executables. Note that the Automation Manager, \SYSTEM32\AUTMGR32.EXE, must be running on all the server computers for the system to function. Once the objects are compiled and copied to the respective computers, here are the steps for setting up the three-tier system:

• On the client computer: Run the pool manager (ObjectPoolMgr) on the client, as it is the next link in the chain, and the only link that the client needs to know about. Running it once registers the object so that RACMan can be used to specify network address, protocol, and authentication level. Then set the access to remote. (For more on RACMan, see "Visual Basic 4.0 Goes Live: 16-Bit/32-Bit Rapid Application Development," Developer Network News, Sept/Oct 1995.)

• On the pool manager computer: Run the satellite object manager (CreateObjectLocalMgr) and ObjectPoolMgr to register them, and then use RACMan to set up the satellite for remote access, supplying the same three parameters as above (with different values, of course). Additionally, you must set up the server to allow all remote activations. You must also register the DLL by running the REGSVR32 utility from the command line:

REGSVR32 <path to DLL>\FinancialCalcDLL.DLL

• On the satellite object manager computer: Run the CreateObjectLocalMgr server and the Visual Basic OLE server FinancialCalc to register them. Then use RACMan to set up the access control list (ACL). In our security model, all users can hit the central pool manager, but only the central pool manager can access the satellite object managers.

Security

There are two types of security in remote automation. The first is access control, which makes sure that only certain types of objects are remotely available, or that only specified users have access to certain objects. The second is authentication, which ensures that data sent from one application is identical to the data received by the other, and that no one intercepts it in between. Authentication merits its own article, so we will address only access control in this example.

Many security architectures are possible with distributed processing, ranging from no security (except for the default domain security), where anyone on the domain can activate OLE servers remotely, to hermetic security, where no one but the logged-on user can run OLE servers on that computer.

For computers running Windows NT, the preferred option (see the ambiguously labeled Client Access tab in RACMan) is Allow Remote Creates By ACL. This option uses Windows NT access control lists to determine whether a user running the client application has permission to access the class. Access to the server is tested by the Automation Manager impersonating the client user and attempting to open the object's CLSID key with query permissions. If the open fails, the Automation Manager returns an error. If the open succeeds, the Automation Manager quits impersonating the client user, creates the object, and returns a reference as usual. (Note that this security policy is dependent on the Windows NT ACLs and security impersonation, therefore it is not available on Windows 95-based server computers.)

For Windows 95 servers, the only secure option available is Allow Remote Creates By Key. Choosing this option in RACMan and selecting the Allow Remote Activation check box enables the system to grant access to an application that has the correct value stored under the object's CLSID in the registry. For Windows 95 servers, you should also set the authentication level to No Authentication.

We designed our architecture to allow unrestricted access (Allow All Remote Creates option) to the central pool manager by all clients. All the clients are set up to point the object reference for ObjectPoolMgr to the central server. The computer running ObjectPoolMgr is configured to know where all the satellite object managers are located, again using RACMan.

When setting up the satellite computers, the Client Access tab on RACMan is used to select the Allow By ACL option. At that point, the Edit ACL button is enabled and the Remote Class Permissions dialog box is displayed.

To restrict access to the OLE objects on each satellite to one external trusted login, remove the default entries in the Name list box for System and Everyone and then add back the domain logon used to launch the central pool manager, ObjectPoolMgr.exe. Only clients requesting services from the ObjectPoolMgr can launch remote servers on the satellites—a requirement if the satellite computers are also users' workstations. The same approach could be used to restrict access to the central computer running ObjectPoolMgr to an approved client list, should another security layer be desired.

Summary

We now have in place the skeleton of an extensible, three-tier distributed system with basic security. The simplicity of the basic building blocks should allow you to enhance this model easily according to your needs.

Robert Eineigl works in Microsoft's Information Technology Group. His nocturnal interests include bicycle design, keyboard improvisation, and wildlife serenades with his custom-made trumpet. Randy Morgan is a strategic account engineer at Microsoft. He hikes, bikes, and kayaks, and his friends describe him as an adrenaline junkie.


The Windows 95 Graphics Architecture

November 1, 1995

The Windows 95 operating system includes an extensible graphics architecture designed to deliver high levels of performance in bitmap graphics, 3-D graphics, and digital video playback. Developers have a choice of APIs, all of which exploit hardware acceleration. Microsoft has unified the display device driver interface so that manufacturers of graphics hardware accelerators need only provide a single, simple-to-install display driver to accelerate the suite of graphics APIs for the Windows operating system.

Although each graphics API targets a particular class of application or area of need, synergy among the technologies enables developers to use as much or as little of the technologies as they need, and to switch between them fluidly.

Which API developers select is determined by the requirements of their applications:

• Productivity application graphics. Applications that require assistance in drawing general-purpose 2-D graphics primitives and fonts use graphics device interface (GDI) functions. GDI now includes the device-independent bitmap (DIB) engine, which provides device-independent raster graphics operations. WinG functionality is now built into the DIB engine as the CreateDIBSection function.

• Digital video playback. Applications designed to play video use the Video for Windows API. Now fully integrated into Windows 95, Video for Windows uses DirectVideo to exploit hardware acceleration and improve video playback.

• Bitmap graphics. System components and applications such as games that require bitmaps to be blasted to the screen as quickly as possible use the Microsoft DirectDraw API, a general-purpose composition engine for raster graphics. (See "Programming for the Windows 95 SDK," Developer Network News, July/August 1995.) DirectDraw exploits the capabilities of today's high-powered 2-D graphics accelerators to deliver frame rates that are faster than those possible with either the WinG API or the CreateDIBSection function.

• Consumer 3-D graphics. Developers creating applications such as games (which require real-time, fully interactive 3-D graphics) use Reality Lab, a comprehensive, real-time 3-D rendering library designed for consumer platforms. See the news article "Microsoft Demonstrates High-Performance Engine and Graphics Accelerator Card for Games on Windows 95" in the For Developers Only section of the World Wide Web (http://www.microsoft.com.devnews) and The Microsoft Network (go devnetnews). Developers creating or porting 3-D applications and games that require the highest degrees of control, flexibility, and performance can use the Microsoft Direct3D API to directly render 3-D graphics and exploit the capabilities of new 3-D hardware accelerators. Reality Lab achieves its hardware acceleration via Direct3D.

• Professional 3-D graphics. Developers creating high-end CAD, engineering, or 3-D modeling applications use OpenGL to deliver the high levels of accuracy required by such applications.

For an illustration of the Windows 95 architecture and a more detailed description of each component, see the technical backgrounder "Microsoft Windows 95 Graphics Architecture" in the For Developers Only, Strategy section of the World Wide Web (http://www.microsoft.com/devonly/strategy) and The Microsoft Network (go devstrat).


Windows NT 3.51 Has International Flair (and Fonts)

Lori Hoerth

September 1, 1995

Windows NT 3.51 added support for the PowerPC hardware platform as well as a number of other features, including some very important international functionality. Combined with the functionality that already existed in Windows NT 3.5, this new international functionality gives users the ability to run localized applications on the English product—for example, the Greek version of Microsoft Excel on the U.S. version of Windows NT.

Windows NT 3.51 provides four main new features important to international customers:

Locale-sensitive fonts: When the language and country are set in the International application in Control Panel, all fonts—including console fonts, system fonts, and application fonts—are reset to match the newly set locale. This allows an English-language system to run the Russian version of Windows 3.x applications and display all characters correctly when the locale is set to Russian.

Keyboard switching application: Microsoft now ships, as part of every version of Windows NT 3.51, an application that allows for quick switches of the systemwide active keyboard layout between a primary and a secondary layout. The keyboard switching application can be activated by running KBDSEL.EXE, as shown in Figure 1.

Figure 1.

Large content application fonts: The Arial, Times New Roman, and Courier New fonts that ship with Windows NT 3.51 are now multicharacter set fonts. These fonts contain glyphs for all European languages (including Greek, Turkish, and English). These same fonts ship as part of the multilingual support on Windows 95. They give users of Windows NT 3.51 more choices of fonts they can use, while still being able to see multiple scripts within the Windows NT shell (that is, File Manager), as shown in Figure 2.

Figure 2.

"Tagged font" mapping: Windows NT 3.51 has added font mappings to enable document compatibility with existing Greek, Central European, and Eastern European documents that have used tagged font face names in the localized Windows 3.x environment. For example, an existing Microsoft Word document that was created on the Greek version of Windows 3.1, using the Greek version of Word 6.0, contains Greek text that was created using a font named Arial Greek. This document is displayable on a Windows NT system, because Windows NT maps Arial Greek to the Greek portion of the multicharacter set font named Arial, thus being able to display Arial Greek using the Arial font that contains Greek glyphs.

The next release of Windows NT, a shell update planned for beta release this fall, will contain all of the new multilingual functionality in Windows 95, as well as a number of enhancements to allow simpler creation of multilingual Unicode applications. A subsequent version of Windows NT, codenamed "Cairo," will increase the number of international- and language-based features in Windows NT by adding content indexing and language-based queries.

Lori Hoerth is a senior program manager for the Windows NT team in Microsoft's Business Systems Division. Her areas of responsibility include international features and functionality, NLS APIs, multilingual computing, Unicode issues and implementation, and character encodings and mappings.


Wireless Communications for Windows 95

Mark Williams

November 1, 1995

The PC connectivity world today is mostly wired, with the cable type dictating the application. A link over a parallel cable means printing, while a link over a serial cable serves a modem. Right now, a user consciously needs to start a connection over the cable that matches the application. Starting a connection is a hassle that many potential computer users just won't put up with.

As time goes on, wireless communications are going to play an increasingly important role in computers, particularly for mobile users. As more wireless PC connectivity hardware and software become available, applications will provide new connectivity features. Applications will initiate connectivity on an as-needed basis, and a user will not even need to know the connection type in order to use it.

Because of its low cost and simple implementation, the first widely available wireless connectivity medium for PCs is infrared (IR). The engineering requirements are straightforward, and the component cost is less than $5 per device. Computer system and peripheral makers are already integrating infrared devices with computers and printers.

Microsoft releases IR-related products

A Microsoft development team that focuses on mobile computing issues has just released its first products: the Infrared (IR) Communications for Windows 95 device driver, and the IR Communications for Windows 95 Device Driver Kit (DDK), which was developed with Hewlett-Packard. The driver is also part of the DDK.

Software developers can get the IR Communications device driver from the Windows Driver Library (WDL) and can install the driver on computers with IR ports to add IR capability to Windows 95. Communicating applications that use serial and parallel cable links can then be tested over the new IR link, which can operate at speeds up to 115.2 kilobits per second (kbps).

Independent hardware vendors (IHVs) and original equipment manufacturers (OEMs) can get the IR Communications for Windows 95 DDK by contacting their Microsoft OEM sales representative. IHVs and OEMs can use the sample IR driver source code as a starting point to build IR drivers that operate with their IR-capable devices. Examples of such IR-capable devices are IR ports built into computer platforms, IR adapters that plug into serial and/or parallel ports built into computer platforms, LAN-access points, remote keyboards, printers, cellular and land-line phones, digital cameras, pagers, home entertainment center equipment, and kitchen appliances.

Based on feedback from computer manufacturers, Microsoft predicts that the majority of new portable PC systems will ship with built-in IR ports that are compatible with Windows 95. For systems without IR built in, Microsoft is working with IHVs that make IR adapters that plug into Windows 95-based computer serial ports and provide IR capability.

Companies that have not thought of themselves as makers of computer peripherals, such as manufacturers of kitchen appliances, home entertainment centers, and cameras, will likely build IR into their devices and become potential Windows 95 IHVs.

The Infrared Data Association (IrDA) has already developed infrared communications standards that are accepted by the computer, communications, home entertainment, and semiconductor industries. (See "The IrDA and Its Standards," below, for a description of the standards.) As long as the makers of these devices strive to comply with the IrDA standards, all these different types of IR devices will be able to communicate with each other and with computers running the IR Communications for Windows 95 device driver. In the rest of this article, the term IrDA-compliant will be used to refer to all these types of IR devices.

Microsoft and IrDA

Microsoft has been an executive member of IrDA since its founding and promotes the IrDA effort to standardize infrared communications protocols across the industry. Microsoft's infrared products are designed to comply with the IrDA specifications. This ensures interoperability between IR-capable computers running Windows 95 and all other devices that support the IrDA specifications.

If you are an independent software vendor (ISV) writing applications for IR-capable computers running Windows 95, IR drivers built with the IR Communications for Windows 95 DDK enable you to use standard Win32 communications APIs to transfer data between IrDA-compliant devices. Many existing applications that communicate over serial and/or parallel cables using these APIs will communicate over IrDA-compliant IR links without any reprogramming.

Microsoft's future IR products will also be designed to comply with the evolving IrDA standards, which will take advantage of the dynamic, ad-hoc nature of the media and hardware advances (such as fast IR data exchange at speeds up to 4.0 mbps).

Scenarios with IrDA-capable devices

People will be able to use their computers in new ways when IR communications are added to Windows 95 and IrDA-compliant devices abound. Here is a tale that illustrates some of these.

In the workplace and on business trips. Most workers will have an IR-capable desktop computer and an IR-capable portable computer. The portable is either "docked" to the desktop or carried with the worker as she roams between office buildings and labs.

To prepare for a meeting, the portable owner downloads the departmental project schedule information from a LAN database to the desktop, adds some late-breaking information that is only on her desktop PC, and then squirts a filtered set of schedule information to the portable using the IR link.

When she arrives at the meeting in a nearby building, all the attendees have IR-capable laptops loaded with their department's part of the schedule. During the beginning of the meeting, each worker uses the laptop to check schedule facts, take notes, revise the dependencies in their schedules, and squirt schedule facts to each other as needed.

During the break, workers with access to an IR-capable LAN access point, which will be available in most meeting rooms, can use laptops to send and receive e-mail messages relevant to the meeting.

After the break, the attendees collaborate on a new schedule by using IR-capable conferencing software on their portables. When a realistic schedule is hammered out, one worker with the agreed-upon schedule on her portable leaves immediately for the airport to fly to a board meeting to present the schedule.

She uses the laptop to continue exchanging e-mail messages in the airport and hotel by using an IR-capable public phone. While in transit, she receives detailed messages about the upcoming board meeting on her IR-capable pager and organizes the messages by squirting them into the IR-capable personal information manager (PIM) application on her laptop.

In a hotel room, she uses the notebook to add the latest schedule information to an electronic slide presentation. In the hotel business service center, she uses the IR-capable presentation graphics software to squirt the slide images to an IR-capable laser printer, producing handouts for the meeting.

At the board meeting, she displays the electronic slides to an audience by squirting them one at a time from the notebook computer to a high-speed IR-capable large screen video projector (some slides have digital video and audio clips that demonstrate the physical processes underlying the schedule dependencies she is presenting).

At home or as tourists. After the board meeting, she takes her family's IR-capable digital camera and one of the family's IR-capable handheld PCs out of her luggage and heads for the sprawling combination super mall/amusement park.

She doesn't have much time, so she immediately goes to an IR-capable information kiosk and downloads a user interface onto her handheld PC through the IR port. She uses the interface to navigate symbolically through the acres of attractions and to query the information kiosk for squirts of detailed information about some of the attractions.

When she locates an attraction her kids are interested in, she walks there and takes some snapshots. When she gets back to the hotel, she squirts the best of the snapshots from her IR-capable digital camera to the IR-capable laptop. She uses the hotel business center to send an e-mail message home that asks her son to pick her up at the airport, with the digital snapshots as attachments.

Meanwhile, her son and a friend are attending a lecture at the local college campus. They use their handhelds to download the class handouts and the next homework assignment from the professor's IR-capable portable computer. They collaborate on the assignment during the lecture, and on the way out they squirt the completed assignment back onto the professor's computer.

In the off-campus CyberCafe, they start going over the lecture notes they downloaded and then surf the Internet, using the cafe's IR access point, looking for information that will invalidate what they have just been told by their professor.

Getting into IR

OK, so maybe the average person wouldn't have such a computer-filled day. However, all the uses described here will become possible. And Microsoft has plans to develop extensions to Windows for other wireless media in addition to IR. Can you imagine other scenarios, especially when other forms of wireless communication, such as radio frequency (RF) or cellular data, are integrated with computers?

Here are some basic suggestions for getting started with the low-cost IR media that is available today:

• Purchase a couple of IR-capable devices designed to be IrDA-compliant.

• Start experimenting with the Microsoft IrDA-compliant IR Communications for Windows 95 DDK.

Purchasing IR-capable devices

Current infrared devices designed to be IrDA-compliant operate over a minimum range of one meter between transmitter and receiver, and within a 30-degree angled cone. The current IrDA specification is optimized for point-to-point links between two or more devices. Keeping the cone angle narrow minimizes problems associated with interference and "hidden transmitters." The first revision of the IrDA specification provides for up to 115.2 kbps serial infrared links. Several notebook computers already include built-in IR ports with these characteristics. These computers include DEC HiNote Ultra, Gateway 2000 Liberty, HP Omnibook, IBM ThinkPad, Midwest Micro Elite, and Texas Instruments 5000.

IR adapters that add IR capability to Windows-based computers by plugging into a serial port are available for as little as US$35 from numerous peripheral manufacturers. See below ("IR Adapter Manufacturers") for the names and addresses of the manufacturers of adapters that have been tested using the Microsoft IR driver.

Printer manufacturers are also supporting IR communications. New printer models, such as the Hewlett-Packard LaserJet 5MP, feature an IR port in addition to the usual serial and parallel interfaces. These printers can communicate wirelessly with portable PCs and other infrared devices.

Experimenting with the IR communications products

Once you have a couple of IR devices that are designed to meet the IrDA specifications, you can use the IR Communications for Windows 95 device driver to start exchanging data between applications using the IR devices. To work with the IR Communications driver, applications must use the Win32 communications APIs.

IHVs and OEMs can use the sample C-language source code in the IR Communications for Windows 95 DDK to develop an IR device driver for new IR-capable devices. The DDK documentation pinpoints the few lines of code you will have to change in the sample IR driver source code to implement your own low-level driver. The IR Communications DDK is available from your Microsoft OEM sales representative.

The IR Communications for Windows 95 SDK will provide a set of APIs and protocols for IR links that go beyond the Win32 communications APIs. These include:

• IR Sockets APIs, which enable application developers to quickly port existing Windows Sockets applications to use IR links.

• File Transfer APIs, which enable application developers to use files as units of transfer over IR links.

• Object Exchange protocol, which enables developers to transfer small units of information (objects) such as business cards, address book entries, or sales transaction records over IR links and keep the objects on different computers in synchronization with each other.

• IrLAN protocol, which enables applications to access information on networks of many different protocols and addressing schemes through an IR port.

Looking ahead, the SDK Beta is scheduled to be available on an upcoming release of the Microsoft Development Platform. The final version of the SDK is slated for release in the second quarter of 1996.

Mark Williams is a senior technical writer in the Microsoft Personal Systems Division. He writes about device drivers and other hardware-related issues.

The IrDA and Its Standards

The Infrared Data Association (IrDA) is a group of computer, telecommunications, and semiconductor manufacturers and consumer products companies that have worked together to define the IrDA specification as an industry standard. By implementing the IrDA standard, member and nonmember companies can create devices that cooperate with each other to share the IR spectrum in a cooperative fashion. For more information about IrDA, contact:

Infrared Data Association
PO Box 3883
Walnut Creek, CA 94598
Tel: (510) 943-6546
Fax: (510) 943-5600
E-mail: irda@netcom.com

Current IrDA standards

• Serial Infrared (SIR) physical layer specification, which provides for serial infrared links running up to 115.2 kbps. Higher-speed physical layer specifications have been approved by IrDA that will support link speeds of 1.152 mbps and 4.0 mbps.

• IR Link Access Protocol (IrLAP) provides a reliable point-to-point link, which effectively replaces a three-wire serial cable connection.

• IR Link Management Protocol (IrLMP) provides for multiple sessions over the single point-to-point link. An Information Access Service (IAS) is also specified through which a device can learn about the services offered by another device.

IrDA standards currently under development

• IR COMM, which provides full emulation of three-wire, nine-wire, null modem, and parallel connections. The emulation sends the state information that is normally maintained by signals on the carrier detect (CD), data terminal ready (DTR), clear to send (CTS), and other communication control lines.

• Tiny TP, which provides a tiny transport protocol to provide session level flow control on a link.

• Object Exchange, which provides a protocol that transfers generic data objects (such as a business card or an address book entry) between applications running on different computers.

IR Adapter Manufacturers

The names and addresses of manufacturers of IR adapters that have been successfully tested with the IR driver executable in the IR Communications for Windows 95 DDK:

ActiSys, Inc.
1507 Fulton Place
Fremont, CA 94539
Tel: (510) 490-8024
Fax: (510) 623-7268
E-mail: corp@actisys.com

Adaptec, Inc.
691 South Milpitas Blvd.
Milpitas, CA 95035
Tel: (800) 959-7274
Fax: (408) 957-7223

Extended Systems, Inc.
5777 North Meeker Ave.
Boise, ID 83713-1520
Tel: (208) 322-7575
Fax: (208) 377-1906


Ask Dr. GUI #24

(Remember, he's not a real doctor. He's just a figment of your imagination.)

May 1995

Have a question? Dr. GUI's busy operating schedule won't allow him to answer all questions, but the Good Doctor will answer as many as he can in the next release of the Microsoft Development Library. Send your questions to:

Dr. GUI
Microsoft Developer Network
One Microsoft Way
Redmond, WA 98052-6399

Fax: (206) 936-7329, Attn: Developer Network
Internet: msdn@microsoft.com

Questions in this issue:

Doc's Rx: Read the Docs Then Use Help

New from Ronco! The Time Slicer!

The Heartbreak of C4275 Warnings

Visual Basic and Properties

__stdcall Functions and Variable Arguments

Renaming Database Fields


 Doc's Rx: Read the Docs Then Use Help

Dear Dr. GUI:

I have been reading your articles for a couple of years. However, I did not need to write Windows-based applications using MFC until recently. The worst thing is that I need to learn how to write Windows-based applications using MFC in a short time. I have been reading Inside Visual C++ from Microsoft Press. It seems to me that there are millions of WM_ messages and class member functions. With some of them, it is obvious what they will do. However, I have not figured out a way to find out what may be available to use in different situations. For someone who knows the basics of how Windows works, the structure of MFC classes, and object-oriented programming, what are the best resources to learn about programming for Windows using MFC?

I would try to memorize all the MFC classes and their member functions and software development kit APIs, if only my memory did not get lost, like my Windows-based applications. I am a Developer Network Level 2 member, and I have purchased all the MFC Windows programming materials that I know of. Now it is time to see my GUI doctor for help. Maybe you can prescribe some medicines to fix my memory problem.

My second question is easy. VLIST, the virtual list box sample in the Microsoft Development Library, is written in C using the SDK. Is there an equivalent example using MFC?

Getting a free T-shirt is nice, but I would rather have Dr. GUI answer my questions. Why don't we make a deal? If you answer my questions, you save a T-shirt. Ha ha!

W. Wong

Dr. GUI replies:

Some medicines are hard to take. The syrups taste bad. The pills are big, and if they don't get stuck in your throat, they upset your stomach. My prescription for you is going to be a hard pill to swallow: Read the documentation. The best tutorial for learning how to use the Microsoft Foundation Class Library (MFC) is the Scribble tutorial in the Visual C++ manual. Following along with the creation of the Scribble sample application will get you on the road to recovery in less than two days' time.

Once you have done the tutorial, there is no need to memorize all the application programming interface (API) functions and classes. You can press f1 to get Help or Books Online while running Visual C++. Even better, leave the Microsoft Development Library running, so that it's just an alt+tab away with answers to your questions.

In most cases, MFC is a loose wrapper around the Win32 API. If you know Win32, you should have little difficulty transitioning to MFC. The biggest difference between an MFC application and most Windows-based applications in C is in the document/view architecture and in the handling of menus. The Scribble tutorial covers these issues very well.

You are definitely on the right track reading Inside Visual C++ and the Development Library.

Regarding an MFC version of VLIST, I'll quote my college physics textbook: "That is left as an exercise for the reader." Seriously, we don't currently have plans to make an MFC version of the VLIST sample. The new hierarchical control introduced by Windows 95 replaces much of the need for an MFC version of VLIST. For more information, check out the wonderful, soon-to-be-published-by-Microsoft-Press book on Windows 95 by Nancy Cluts, which contains every sample on the Development Library CD in C, C++, MFC, Small Talk, SNOBOL, and Swahili.


 New from Ronco! The Time Slicer!

Dear Dr. GUI:

Can time slices be preempted on Windows NT? In other words, if a higher-priority thread becomes ready, will the lower-priority thread be preempted within a time slice, or after the time slice? Also, do you need to raise the thread's priority to real-time critical to do that? Can the user change how long a time slice is? Any other information on Windows NT and real time would be helpful.

A developer who sought your consultation at a conference

Dr. GUI replies:

This is a common question. However, before I answer it, I need to make the appropriate disclaimer. All of what I am about to say is subject to change. You should design your product in such a way that you can easily flow with the tide.

Okay, let's talk about the current situation. When a higher-priority thread becomes ready to run, the current thread is preempted. Time slices under Windows NT do not vary in length, except when a thread's priority is temporarily boosted to prevent priority inversion or starvation. There is a lot of information about multithreading on the Microsoft Development Library CD. Jeffrey M. Richter deals with it in his book Advanced Windows NT, while the Developer Network's Ruediger Asche has written seven articles on the topic for the Development Library. Also, keep your eyes open for Development Library content dealing with Windows NT interrupt response time and latency. We are acquiring more on this topic.


 The Heartbreak of C4275 Warnings

Dear Dr. GUI:

I've used the DECLARE_SERIAL and IMPLEMENT_SERIAL macros in some classes I'd now like to export from a DLL. But I'm having some trouble linking. There were a bunch of warnings—C4273, C4251, and C4275, to be specific. I've #pragma'd them out for the time being. But I'm getting another error now:

C:\USERS\DEFAULT\src\bbsched\lib\src\schevent.cpp(83) : error C2491: 'CBWeeklyEvent::classCBWeeklyEvent': definition of dllimport static data member not allowed

The offending line is:

IMPLEMENT_SERIAL(CBWeeklyEvent, CObject, SERIALIZE_VERSION);

I'm not sure what I can do about this. Clearly, there must be some workaround, otherwise MFC couldn't use IMPLEMENT_SERIAL in any of its exported classes. What's the answer?

Frustrated Linker

Dr. GUI replies:

I assume that you are using an extension dialog. I had this problem with an extension. I fixed it by changing the _AFXDLL preprocessor flag to _AFXEXT.

C4275 warnings are to be expected. They are just telling you that a Microsoft Foundation Class Library (MFC) base class you are using isn't exported from the dynamic-link library (DLL). However, this doesn't matter because the MFC classes are in the shared DLL. It would matter if the base class were your own class.


 Visual Basic and Properties

Dear Dr. GUI:

Using Visual Basic, how do you get the value of a property (Tag, in this case) of a control on a form when all you have is the control's hWnd?

Thanks for the help.

Cris Williams

Dr. GUI replies:

You must walk through the Controls collection (and possibly the Forms collection) until you find it. The code is simple:

Function TagFromWindow$ (Hwnd As Integer)
On Error Resume Next
For i% = 0 To Forms.Count - 1
If Forms(i%)..hWnd <> Hwnd Then
TagFromWindow$ = Forms(i%).Controls(j%).Tag
On Error GoTo 0
Exit Function
End if
For j% = 0 To Forms(i%).Controls.Count - 1

If Forms(i%).Controls(j%).hWnd <> Hwnd Then
'If Control has No Hwnd this gets executed
Else
TagFromWindow$ = Forms(i%).Controls(j%).Tag
On Error GoTo 0
Exit Function
End If
Next j%
Next i%
On Error GoTo 0
End Function

The main trick is handling controls that do not have an hWnd. This is done by using On Error Resume Next and testing for inequality. If a control does not have a property, it is deemed to be not equal.


 __stdcall Functions and Variable Arguments

Dear Dr. GUI:

I've spent the day on this. I'm fed up and in desperate need of some kind soul to point out the error of my ways. I'm trying to call a COM object interface function (somewhat indirectly) from a piece of code in a DLL built with Visual C++. The function I want to call uses the __stdcall convention (that is, it cleans up the stack before returning to the caller). What I'm seeing is that both the caller and the callee are cleaning up the stack—hence, kaboom!

Forgive the somewhat primitive nature of the code here, but I have resorted to very small steps in order to see what's going on in the debugger:

typedef HRESULT (__stdcall METHOD)(...);
typedef METHOD* PMETHOD;
typedef PMETHOD* PVTABLE;
typedef PVTABLE* POBJIFACE;
STDAPI comCallStdMember3(IUnknown* pInterface, DWORD dwIndex, DWORD dwArg1,
  DWORD dwArg2, DWORD dwArg3)
{
POBJIFACE pObjIface = (POBJIFACE)pInterface;
PVTABLE pVtable = *pObjIface;
PMETHOD pMethod = pVtable[dwIndex];
HRESULT hr = pMethod(pInterface, dwArg1, dwArg2, dwArg3);
return hr;
}

This code is called from Visual Basic (not that it matters). The call executes correctly, but on return the stack gets an additional cleanup, which should not happen.

Mark Thompson, age 2 (his father was ashamed to admit that he did this)

Dr. GUI replies:

I must say you have an extremely advanced understanding of coding—and of the English language—for someone your age, Mark. I must consult Piaget about this. But to answer your question: The problem is with your definition of METHOD. There is no such thing as a __stdcall variable argument function as you have defined it, so the __stdcall is silently ignored. Variable argument functions are always cleaned up by the caller (__cdecl), since the caller is the only one that knows at compile time how many arguments were really passed.

So, you call comCallStdMember3, which in turn calls METHOD. METHOD returns and cleans up the stack. Then comCallStdMember3 returns and cleans up the stack. Hence, kaboom!

You'll have to use individual, nonvariable argument function pointer typedefs instead.


 Renaming Database Fields

Dear Dr. GUI:

I am currently writing a Visual Basic application that uses Microsoft Access 1.1. I faced a big problem to rename a fields-in-access table with Visual Basic. Is there any way to rename a field (field name) with Visual Basic language? Since I have a batch of database files (around 700), I want the process to be automated.

Eddie Cheung

Dr. GUI replies:

No problem, Eddie. First you must create a new table with the new names, then copy the table. The structured query language for it would be:

Dim DB As database
Set DB = OpenDatabase("C:\MyData.mdb")
DB.Execute "SELECT DISTINCTROW Authors.Author AS [New Author] INTO [New Author]
  FROM Authors;"

After copying the table, you can delete the original version and rename the new one with the original name.


Above and Beyond the Windows 95 Logo

Scott Henson

September 12, 1995

You're ready to ship your new application to the hungry masses. You've been working hard on it and have diligently followed the logo requirements for the Windows 95 operating system. What more can there possibly be?

Actually, there is more you can do to make your application a model citizen of the Windows 95 universe. Let's look at some ways you can tightly integrate your application design with Windows 95 to make the user's OBE (out-of-box experience) a time of exultation.

No code need apply

There are six quick and easy things you can do to integrate well with the shell without writing any code.

1. Provide all appropriate icons. In addition to providing an icon for your application, make sure you use a separate icon for every single file type your app understands. Keep in mind that extensions will be turned off by default, so users will need a visual cue.

The Windows 95 shell supports three icon resolutions: the familiar 16 x 16 and 32 x 32 icon formats—which are authored in 16 colors—plus a higher-resolution 48 x 48 format, which you should author in 256 colors.

Currently there are no commercial tools available to author the 48 x 48 x 256 icon format, so Microsoft has provided a MAKEICON utility that lets you make these icons from bitmaps.

2. Add custom commands for file objects. Windows 95 allows users to focus directly on their documents and manipulate them directly from the shell through the selection of commands (also known as verbs) on pop-up and system File menus. You should provide users with a list of the most common commands for your document types. A simple (yet good) example of this is when you right-click an .AVI file and you get the Open and Play commands. A quick look in the registry (run REGEDIT.EXE for Windows 95 or REGEDT32.EXE for Windows NT) reveals that these commands have been registered under the HKEY_CLASSES_ROOT main key as follows:

avifile = "Video Clip" (this is where you

register your friendly name)

shell = "play" (the default verb)

open = "Open" (what shows up on your menu)

command = "c:\windows\mplayer.exe %1" (what

gets executed)

play = "Play"

command = "c:\windows\mplayer.exe /play /close

%1"

3. Support ShellNew for documents. This feature allows the user to create a new document without launching an application or using the Open/Save As commands on the File menu. This is a great example of the new "document-centric" paradigm in Windows 95, enabling users to concentrate more on their documents and less on the tool that authors them. All ShellNew entries are entered as a value in the registry under the HKEY_CLASSES_ROOT\<filename extension> key. For example, the path for a text file would be HKEY_CLASSES_ROOT\.txt\ShellNew.

ShellNew supports four types of document creation:

• Empty File: Creates a zero-length file. Use NullFile with "" as its value

• Data Stream: The document will begin with the data stream you enter. Use Data with string, binary, or DWORD values.

• Template: Points to a document that is used as the standard template every time you create a new file from the shell. Use FileName with the value being a fully qualified path to the template file.

• Command: Allows an application to launch when the user wants to create a new file. This is great for wizard support. Use Command with a value pointing to the command to be executed.

4. Support the PrintTo verb. This allows the user to drag and drop a document to any printer (and is a must for interoperating well with the faxing services in Windows 95). Consider implementing this feature in your application design so that no user interface appears (you may want to put up a Print dialog box to indicate progress). Here's a quick example of how .BMP files (Paint.Picture is the application identifier for .BMP files) implement the PrintTo verb:

HKEY_CLASSES_ROOT\Paint.Picture\shell\printto\

command = "C:\PROGRAM FILES\ACCESSORIES\

MSPAINT.EXE" /pt "%1" "%2" "%3" "%4"

5. Register user-specific custom sound events. Your application can register specific events to which the user can assign sound files. To register a sound event, create a key under the HKEY_CURRENT_USER key. For example:

HKEY_CURRENT_USER\AppEvents\Event Labels\

EventName = Event Name

Set the value for EventName to a user-readable name.

Registering a sound event only makes it available in Control Panel so the user can assign a sound file. Your application must provide the code to process that event.

6. Use OLE structured storage compound file format for your documents. Additional property sheets are added to your document property page in the system if you use structured storage as your document format. You will get two new tabs, one for Summary Information and one for Statistics, that allow the user to add and track richer information on documents. Author, Keywords, Comments, Title, Subject, and Last Saved By are some of the attributes that structured storage allows to be displayed in the shell. In addition, summary information will show up as extended attributes in Microsoft Exchange.

Do as Windows 95 does

The ultimate application for Windows 95 will behave just as the system does—not only in look and feel, but also in the way that operations such as drag and drop are performed. The key thing to concentrate on is leveraging users' experience with the system and not forcing them to relearn how to perform the same task in your application.

Here are the six key components to being consistent with Windows 95.

1. Display long filenames correctly. Displaying filenames correctly means stripping the .3 extension from the end of the filename, so users see names such as "My Amazing Document" instead of "My Amazing Document.DOC".

Users can toggle this option in the user interface, so make sure you are consistent with what should be displayed. To get the proper display name, use the SHGetFileInfo API. This recommendation applies to all places in which you display filenames; make sure your most recently used (MRU) list reflects it. If your application is designed as a single-document interface (SDI), make sure the document name is first, followed by the application name.

2. Handle data transfers consistently with the shell. Keep these critical things in mind when transferring data around the shell:

• Support OLE drag and drop extensively to enable users to move data to and from the desktop, folders, and other applications. You no longer need to support Windows 3.1 drag-and-drop messages in Windows 95. OLE does this for you. Your container should accept both default (using the primary mouse button) and nondefault (using the secondary mouse button) drag-and-drop operations. For a primary drag, accept a data object using the clipboard formats CF_HDROP (a double-null-terminated list of fully qualified filenames) and CFSTR_FILECONTENTS (the contents of one or more files in a format that can be written to a file). This will allow you to accept files from either the system or another application.

• Be sure to support dragging with the secondary mouse button with a context menu at the end. If your application supports links into its documents, be sure to offer a link in your document on a drag out. This applies to drag and drops into and out of your container. If data is selected, include link support using the CF_LINKSOURCE clipboard format, as well as the CF_EMBEDDING format for creating a scrap.

• Be sure the menu-based transfer model in your app will work well with the one in the shell. Test such scenarios as copying a shortcut or file in the system, and then pasting it into your application.

3. Use the common dialog boxes, especially for the Open and Save As commands on the File menu. If you use the system-supplied Open/Save As dialog boxes, you will get shortcuts, long filenames, and direct browsing of the Network Neighborhood for free. You can still extend the dialog boxes using dialog templates similar to Windows 3.1. If you don't use these templates (or if, for other reasons, you need to display files or the system hierarchy), be sure your Open/Save As dialog boxes support all of the following features to maintain consistency:

• Display a name space hierarchy that's the same as the one in Windows 95. This means Desktop is the root, followed by everything on the desktop: My Computer, Network Neighborhood, and so on.

• Display shortcuts (.LNK files) to the document type that has been chosen as the File Type in the dialog box. For instance, if a user wants to see all of the .BMP files (either by entering *.bmp as a file filter or by choosing Bitmap Image as the file type), you should display all shortcuts to .BMP files with the bitmap files themselves.

• Display files with their correct icons and with their .3 extensions stripped (if the user has chosen this option).

• Browse the Network Neighborhood hierarchy directly.

• Take advantage of other miscellaneous features (context menus, property sheets with extensions, details view, and the ability to delete, rename, quickview, and move files).

This is a great deal to have to implement on your own, but if you still want to roll your own, Nancy Cluts provides a great example of using the IShellFolder API to do a lot of this in Programming the Windows 95 User Interface, available in the Development Library or from Microsoft Press. (Look for the ENUMDESK example in Chapter 14.)

Be sure your visuals and control interactions are consistent with Windows 95. Users can change just about everything visually in Windows 95. So, here are the things you should pay attention to:

• Respond to the WM_SETTINGCHANGE message, and query the system colors and system metrics by using GetSysColor and GetSystemMetrics, respectively. Ensure that you make no assumptions about the size of controls and the color of system visuals, especially the 3-D gray color.

• Respond to the WM_DISPLAYCHANGE message (which is sent when the user changes the resolution of the system on the fly), and adjust your UI according to the amount of screen real estate available.

• Take advantage of new system-supplied common controls, and use them in the same consistent manner as Windows 95.

• If you're adding 256-color support, use the halftone palette like the shell. This will avoid palette hits when you switch between the shell and your application.

4. Maintain a consistent object paradigm. This means you should use the document name as the primary title bar text for your application window. It also means that, just as the shell does, you should use context menus on the mouse-up of the secondary mouse button on controls and application content.

In addition, follow the new OLE UI guidelines. Update your OLE UI to include these items:

• Support the new "object properties" dialog box for your embeddings.

• Make sure your icon visualization for embeddings is consistent with the shell. When a user drags an icon from the shell into your container, the icon and name should be the same as it is in the system.

• Make sure you support interactions with icon embeddings the same way the shell does. Icon embeddings should select like icons in the shell, with a highlight-color dither rather than a rectangle with resize handles. The OLE links icon should have arrow-like system shortcuts, and OLE links that are viewable data should get a shortcut arrow on a resize handle when selected.

• Support shortcuts correctly. If the user opens a shortcut (even by dragging and dropping it onto your application), be sure to dereference it before opening it. There are helper member functions in the IShellLink interface. Also, be sure to preserve the creation and modification dates if you edit files by creating a temp file. Shortcuts rely on the creation date to reconcile a lost shortcut target. You can use the Stat and StgSetTimes member functions of the IStorage interface.

5. Facilitate consistent installation and removal of your application. Some key points:

• Place a single icon (shortcut) for your main application directly in the Start Menu/Programs folder so your application can be easily launched from the Start menu. Do not overpopulate this menu. Consider prompting the user during setup to choose which icons to add.

• Support the AutoPlay feature by using the AUTORUN.INF file in your root directory so that the system automatically runs your installation program when the user inserts a CD. It's best to allow users to express their intentions when the CD is inserted. They may want to open some clip art, execute a tutorial, or just browse the contents. Provide a splash screen that allows the user to choose from all of the intended options and, at a minimum, to cancel.

• Register your application properly according to the guidelines so that users can see friendly names for your document types, and so they can uninstall your application from the system-supplied Add/Remove Programs applet in Control Panel.

• Install all of your applications under the Program Files directory.

• Support uninstall (this one is required to get the logo).

6. Support Windows-specific Help features. To be consistent with the way the new WinHelp works in the Windows 95 UI, applications should at least provide context-sensitive pop-up help for the controls in your dialog boxes and UI, and use secondary windows for procedural help. Take advantage of shortcut buttons and resizable topic windows to make Help shorter and easier to read.

But wait, there's even more...

There's lots, lots more. For the ultimate in UI flexibility, there are some exciting ways to tie into the Windows 95 UI. These include useful shell extensions (property sheet handlers, icon handlers, context menu handlers, data handlers, drop target handlers), taskbar status notification icons, Passwords Control Panel integration, file viewers and file parsers, and briefcase reconcilers. Here are two excellent starting points to get the inside scoop:

• Programming the Windows 95 User Interface by Nancy Cluts

• The Windows Interface Guidelines for Software Design (especially Chapter 10, "Integrating with the System")

But what about Windows NT? Good question. "Extending the Windows 95 Shell" by Nancy Cluts (Developer Network News, July/August 1995) outlines considerations for running shell extensions on Windows NT (it's good reading). Ultimately all of this will simply work on Windows NT, with no additional code needed, when the Windows 95 shell for Windows NT is released (sometime early next year). You can get a head start now with the pre-release version of the Windows 95 shell update for Windows NT, which is included on the Development Platform.

Special thanks to Joe Belfiore, the program manager for the Windows 95 shell, for providing initial inspiration for this article (and for helping put together a pretty cool UI).

Scott Henson works in the Developer Relations Group, where he spends his every waking moment (between noon and 3 p.m.) trying to help developers unravel the mysteries of writing great apps for Windows 95 and Windows NT.


Common IME System on Far East Windows 95

Nadine Kano

September 12, 1995

Input method editors (IMEs), also called front-end processors, are applets that allow users to enter the thousands of different characters used in Far East written languages with a standard 101-key keyboard.

An IME consists of an engine that converts keystrokes into phonetic and ideographic characters, and a dictionary of commonly used ideographic words. As the user enters keystrokes, the IME engine attempts to guess which ideographic character or characters the keystrokes should be converted into. Conceptually, IMEs are the same as keyboard drivers—they simply handle more characters, and Far East systems require some extra code to handle them. When the IME program is active, it traps all keyboard events, including virtual keys.

Far East editions of Windows NT 3.5 and Windows 95 support popular input methods, such as phonetic, code point, or radical-based input methods. The Windows NT 3.5 IME model is compatible with the Windows 3.1 IME model, but both Windows 95 and Windows NT 3.51 implement a new IME model that makes application development simpler and more flexible.

The IME system

The IME module in the Windows operating systems fits into a larger mechanism. Unless you are writing an IME package or customizing your IME user interface (UI), you don't need to worry about the other components, but it is still a good idea to understand what they do.

In Windows NT, the input method profiler (IMP) keeps track of the IME applets installed in the user's system. It stores information about each IME, such as whether it is currently active. Control Panel calls the IMP API to add, delete, or activate an individual IME. More than one IME can be installed on the system, although with Windows NT 3.5, only one may be active at a time.

In Windows 95, multiple IMEs are handled through the multilingual API (instead of by an IMP). Windows stores information about each IME installed on the system in the system registry. Users switch IMEs the same way they would switch among Western keyboard layouts, by clicking the input language menu on the taskbar or entering a shortcut key combination. The change is reflected on the taskbar indicator.

The input method manager (IMM) manages communication between IMEs and applications. In Windows NT 3.5, the IMM API is called almost exclusively by the system. Applications can call two IMM functions: WINNLSEnableIME, which enables or disables an IME, and WINNLSGetEnableStatus, which returns the enabled or disabled status set by WINNLSEnableIME. In Windows 95, the IMM is an extension of USER.EXE, and fully IME-aware applications can call a number of IMM APIs to customize the IME UI.

IME support on Windows 95

With Windows NT 3.5, a single IME covers all subsystems, including Win32, Win16, console, virtual DOS machines, and OS/2. Implementing support for IMEs on Windows NT 3.5 involves adding code to handle a couple of window messages and adding calls to several APIs.

IME support on Far East editions of Windows 3.1 and Windows NT 3.5 differed slightly depending on the target language. The differences were inconvenient for developers; since IME-related code had to be customized depending on the target language, sharing a common code base among Far East editions of an application required additional work.

The designers of Windows 95 therefore decided to create a common IME system for Far East editions of Windows 95 to give applications more control over mechanisms handled exclusively by the IME module on Windows 3.1. For example, on Windows 95, applications now have the option of trapping and responding to messages before the IME processes them. Applications that contain code to support Windows 3.1- or Windows NT 3.5-based IMEs will still run correctly on Windows 95 (as long as the application executable is marked as compatible with Windows NT 3.5 or an earlier version).

Three levels of IME support

There are three discrete levels of IME support for applications running on Windows 95: no support, partial support, and fully customized support.

IME-unaware applications basically ignore all IME-specific window messages. Most applications that target single-byte languages will be IME-unaware. IME-unaware applications inherit the default UI of the active IME through a predefined global class, appropriately called IME. This global class has the same characteristics as any other Windows-based common control. For each thread, Windows 95 automatically creates a window based on the IME global class; all IME-unaware windows of the thread share this "default IME window."

IME-aware applications

IME-aware applications can create their own IME windows instead of relying on the system default. Applications with partial IME support can use this "application IME window" to control some IME behavior. By calling the ImmIsUIMessage function, applications can pass messages related to the IME's UI to the application IME window, where the application can process them. The following code would appear in the application IME window's window procedure.

If(ImmIsUIMessage(hIMEWnd, uMsg, wParam,

lParam)==TRUE) {

switch(uMsg) {

case WM_IME_COMPOSITION:

if(lParam & GCS_RESULTSTR) {

hIMC=ImmGetContext(hWnd);

ImmGetCompositionString(hIMC,

GCS_RESULTSTR, lpBufResult, dwBufLen);

ImmReleaseContext(hWnd, hIMC);

}

break;

}

return 0;

}

The same window procedure could call SendMessage to reposition the status, composition, or candidate windows, or to open or close the status window.

Other API functions that allow the application to change window positions or properties are ImmSetCandidateWindow, ImmSetCompositionFont, ImmSetCompositionString, ImmSetCompositionWindow, and ImmSetStatusWindowPos. Applications that contain partial support for IMEs may use these functions to set the style and position of the IME UI windows, but the IME dynamic-link library (DLL) is still responsible for drawing them.

In contrast, applications that are fully IME-aware take over responsibility for painting the IME windows (the status, composition, and candidate windows) from the IME DLL. These applications can fully customize the appearance of these windows, including their positions on the screen and which fonts and font styles are used to display characters in them. This is especially convenient for programs such as word processors that rely heavily on text input and want to interact with IMEs in a way that is as natural as possible for the user. The IME DLL still determines which characters are displayed in IME composition and candidate windows, and it handles algorithms for guessing characters and looking them up in the IME dictionary.

Fully IME-aware applications trap IME-related messages in the following manner:

1. They call GetMessage to retrieve intermediate IME messages.

2. They process these messages in the application WindowProc.

3. They call TranslateMessage (part of the IMM) to pass the messages on to the IME DLL. The IME needs to remain synchronized, the same way keyboard drivers need to remain synchronized with dead keys.

For example, when the user presses a key, the system generates a keyboard event. USER.EXE checks to see if the currently active HKL (input language handle) points to an IME. If so, it passes the keyboard event to the IMM, which passes the event to the IME. If the IME wishes to respond to the keyboard event, the IME will translate the keyboard event into the virtual key, VK_PROCESSKEY, which it passes back to the IMM. The IMM then sends this virtual key to the application.

If the application wants to customize the IME UI, it should trap VK_PROCESSKEY. It calls ImmGetVirtualKey to translate the VK_PROCESSKEY into a more specific virtual key value, and responds accordingly.

IMEs on Windows 95 keep track of state information for each application running on the system. Each IME stores status information in an internal structure called an input context. Because Windows 95 creates and assigns a default input context to each new thread, individual applications use separate input contexts. Within an application, each newly created window inherits the application's default input context, which is a shared resource.

It is possible to override the default input context by creating and maintaining your own input contexts. The next section describes how to do this.

Customizing IME support in Windows 95

While applications with partial support may reposition the IME's UI windows or change the fonts used to display characters, fully IME-aware applications create and maintain their own input contexts and draw the IME's status, composition, and candidate windows themselves.

Windows 95 provides a number of API calls for communicating closely with IMEs. Since IME DLLs still contain the code that converts keyboard strokes into characters and determines candidate lists, applications need to query IMEs for information on composition strings and candidate lists before they can draw any windows. Applications also need to ask IMEs for status information, such as whether the IME is open or closed and what the current input mode and sentence mode are.

To get or set IME status information, composition strings, or window positions, your application needs to send a handle to an input context to most API calls. Calling ImmGetContext will retrieve the default input context that the system has created and associated with all the windows of a particular thread. Once you are done with the input context, you need to release it by calling ImmReleaseContext. Be forewarned that the system's default input context is a shared resource—any changes to it will affect other windows in the same thread. To avoid this, you can create a custom input context—changes you make to a custom input context will only affect those windows you associate with it.

Before you associate a window with a custom input context, it's a good idea to save the window's default input context. You may need it later—for example, if you destroy your custom input context and need to restore the default.

To create an input context, call ImmCreateContext. To associate this context with a window, call ImmAssociateContext. Once you have associated an input context with a window, the system will automatically provide the input context when the window gets the focus. If you make changes to the input context, you should call ImmNotifyIME so that the IME can remain synchronized. To destroy the custom input context before you terminate your application, call ImmDestroyContext.

Fully IME-aware applications should handle most WM_IME messages. In general, the WM_IME messages tell the application that something has changed and that the application should query the system to get updated information. For more detailed information on these messages and the functions that your application should call in response to them, consult the FULLIME example that ships with the Far East Win32 SDK.

With the help of several API functions, you can be very creative in how you customize the UI for any or all of the IME windows.

If you plan to customize the candidate or composition windows, you should familiarize yourself with the CANDIDATELIST, COMPOSITIONFORM, and CANDIDATEFORM structures, plus the flags and style bits associated with these structures and related functions. The Win32 SDK documentation provides detailed descriptions.

For example, the ImmGetCompositionString function can give you a great deal of information about the string displayed in the composition window. It can tell you if the string contains the characters the user has entered, the characters resulting from the conversion, characters that have been selected but not yet converted, or characters that have been converted and are still selected. The function can also tell you which characters in the string constitute clauses and what position they hold in the composition string, where the cursor is positioned, and which characters the user originally entered.

If your application is very text intensive, it will probably benefit greatly from the extensive customization available with the new IME model. Applications that accept some text input will benefit from the functionality that Windows 95 and Windows NT 3.51 provide through partial support. Even applications that are completely IME-unaware will automatically inherit some IME functionality from the system. Developers and users alike will benefit from this new model—it's more consistent across all Far East editions of Windows and is thus easier to implement. In addition, it allows applications to integrate IME support in a creative and seamless fashion, making text input more intuitive for users.

This article is adapted from Developing International Software for Windows 95 and Windows NT by Nadine Kano, published by Microsoft Press earlier this year.

Nadine Kano is a globalization guru in the Developer Relations Group. She has typed her fingers to the bone writing Developing International Software for Windows 95 and Windows NT.


Developer Network Now Offers BackOffice Test Platform

September 12, 1995

The Microsoft Developer Network (MSDN) has inaugurated a Level 3 membership that will provide developers with all the server components of the Microsoft BackOffice family for developing and testing BackOffice applications.

Specifically, Level 3 members will receive the BackOffice Test Platform, a set of CDs with the latest released versions of all five components of BackOffice version 1.5: Windows NT Server, Microsoft SQL Server, Microsoft SNA Server, Microsoft Systems Management Server, and Microsoft Mail Server. In addition, Level 3 members will receive the Microsoft Exchange Server Beta 2 and the BackOffice Software Development Kit (SDK). (After this, the BackOffice SDK with be shipped as part of the Development Platform.)

The BackOffice Test Platform will be available as a special five-connection-limit version of BackOffice, designed to provide an easy-to-administer licensing model for developers.

In addition, an annual Level 3 membership includes four regular quarterly updates for the year, plus special "off-cycle" premium shipments of important BackOffice releases, such as Microsoft Exchange and the server version of "Cairo," the next version of Windows NT.

"With Level 3 we're extending the MSDN model to client-server development using BackOffice," explained MSDN business unit manager John Rae-Grant, as he tried to concentrate on playing a particularly challenging six-diamond bid during an international bridge tournament in Milan, Italy. "The idea is to put the most up-to-date technology in the hands of the widest array of BackOffice application developers."

Level 3 members also get all the benefits of a Level 2 membership, which includes quarterly releases of the Development Platform and the Development Library and six issues of this rag per year.

Level 3 members in the United States and Canada also receive four phone support incidents, which provide one-on-one help for their development needs. Two support incidents are provided for the SDKs, DDKs, and operating systems that are part of the Development Platform; the other two are provided for BackOffice setup and installation support issues. Please note that "mission-critical" support and "quick fixes" are not included with Level 3 membership, but are available through the Microsoft Support Network.

Moving to client-server development

"With Level 2, MSDN has provided developers client-server technology via Microsoft's SDKs and end-user operating systems," MSDN group product manager Keith Szot noted. "Now with Level 3, MSDN is trying to provide greater focus on client-server development by also delivering the back-end platform technology for testing and development."

All BackOffice server components share the same Win32 API and OLE component software technology. In addition, the same Win32 API is used on both the client and server ends. This means that developers don't have to learn two sets of APIs to develop an application.

"With Level 2, we tried to make it as easy as possible for Windows developers to get a wide range of systems technology from one source," explained Development Platform program manager Steve Molstad as he rushed out of a Redmond 7-Eleven clutching a Big Gulp®. "Now we are trying to extend that approach to developing and testing server-side apps. Hopefully, with Level 3, developers won't have to worry about keeping up with the latest BackOffice components. They'll be assured of getting them in a timely way with the quarterly releases of the Test Platform."

Providing BackOffice technical articles and samples

In its quest to provide developers with real-world, useful information and guidance, along with the BackOffice components, MSDN has unleashed some of its best development talent on BackOffice. Those infamous MSDN development technology writers Dennis Crain and Nigel Thompson have created a fictitious company called NADTEC, using only shipping versions or publicly available beta versions of Microsoft products. "NADTEC is about two guys trying to make heads-or-tails of BackOffice and letting the world benefit from their explorations and solutions," Crain explained.

MSDN subscribers can interact with NADTEC through the Internet and direct dial-up phone lines. In effect, they can use NADTEC's experience to observe and learn from the process of setting up and using a BackOffice environment. They can also see how to develop for the Internet, use e-mail gateways, and configure BackOffice servers.

Thompson and Crain are using their NADTEC experience to write technical articles and sample code that address and solve common issues faced by BackOffice developers. "We hope to provide a great demonstration of what a small company can do to develop tools and content for the Internet," Thompson said.

To see what NADTEC has on the Internet, go to http://www.nadtec.com.

Level 3 pricing and licensing

The licensing scheme for the BackOffice Test Platform shipped through Level 3 is different from the full BackOffice package. It is limited to five connections to the products on the BackOffice Test Platform at any one time. This licensing scheme is designed to provide developers with an easy-to-administer, cost-effective way to develop and test BackOffice applications. Development teams do not need to purchase any additional client licenses to connect to the Test Platform.

Level 3 will be available in September, approximately two weeks after the release of Microsoft BackOffice 1.5. MSDN is offering special introductory pricing to encourage early enrollment in the new Level 3 program. Until December 15, 1995, a one-year subscription costs US$1195 ($1675 CAN). A Level 2 upgrade to Level 3 is US$995 ($1395 CAN).

After December 15, 1995, the cost of Level 3 will be US$1495 ($2095 CAN), and a Level 2 upgrade will be US$1195 ($1675 CAN). Taxes, shipping, and handling charges will be additional.

MSDN expects to roll out Level 3 on a worldwide basis in September. For more information on Level 3 in the United States and Canada, please call (800) 759-5474. Outside the U.S. and Canada, please contact your local MSDN program.


Development Library Viewing Engine Merged into Visual Tools Development Environment

J. Keith Bankston and Peter Lancaster

September 12, 1995

During the last year, the Developer Network and the Visual C++ group have collaborated to merge the features of the Development Library's viewing engine into the Microsoft Developer Studio, the Visual C++ 4.0 new development environment.

The result is called InfoViewer 3.0, which is the Development Library's current InfoViewer engine fully merged into the Developer Studio. (See "New UI Features for Development Library" by Mike Colee, Developer Network News, July/August 1995.)

The purpose of this joint effort was to create a single viewing technology so users could share information between the Development Library, Developer Studio, and other products using InfoViewer. Because many people employ both products, it didn't make sense that incompatibilities between the two viewing technologies denied people programming in Visual C++ easy access to information in the Development Library.

Users of the Development Library alone will continue to get InfoViewer on the CD. If, however, they install any of several new Microsoft development tools that use Developer Studio, including Visual C++ 4.0, Fortran PowerStation 4.0, or Microsoft Visual Test 4.0, they will get the combined advantage of both the Developer Studio and the Development Library.

The additional features in the Developer Studio include dockable windows, customizable toolbars, and a Microsoft Office-like interface.

The advantages of integration

Developer Studio with the InfoViewer component is the common design environment of Visual C++ 4.0, Fortran PowerStation 4.0, and Visual Test 4.0. The result of this work is integrated information and development systems with a single common interface.

What are some of the advantages of this integration? First of all, you can use the InfoViewer component of Developer Studio to open Books Online or the Development Library from Visual C++ 4.0, Visual Test 4.0, or Fortran PowerStation 4.0. For all of these products, the user interface and functionality for online documentation are the same. If you are programming with a development tool such as Fortran PowerStation 4.0, for example, you can press F1 on a keyword in a source file and get information on that keyword contained in the Development Library if you want.

There are also other new features for Books Online users that come with InfoViewer, such as glossary pop-ups, See Also drop-downs, and, within the Developer Studio, drag-and-drop copy and search integration.

If you are working in any Developer Studio-based product, you'll also be able to open information titles from other Microsoft products, such as TechNet and Visual Basic 4.0, that use InfoViewer as a viewing engine for their documentation. F1 can search these titles for information on a keyword as well.

Finding it in the Development Library

Developers who subscribe to the Developer Network can now take advantage of this integration. The Development Library serves as a one-stop source for all Microsoft online product documentation for developer-related products. You can now use the Development Library in place of the individual documentation for Visual C++, Fortran, and Visual Test, plus have access to the documentation for software development kits (SDKs) and device driver kits (DDKs), technical articles, online books and periodicals, and Knowledge Base articles in the Library. On top of that (here comes the plug!), the Development Library is updated quarterly and contains the most recent documentation for these products.

Check it out. We've received lots of requests for this integration. We hope you'll like it. As always, we expect to hear from you about any problems.

J. Keith Bankston is a program manager and longtime slacker in the Development Library technology group. He worked himself into a frenzy to deliver InfoViewer 2.5 and InfoViewer 3.0. Peter Lancaster is a program manager for Visual C++. He worked on InfoViewer and is interested in every letter in the alphabet, and he white-water kayaks with Developer Network writer Dale Rogerson.


Fortran PowerStation 4.0 Targets Code Migration and Reuse

Sunil Alagade

September 12, 1995

Microsoft's development system for Intel is designed to allow developers to more easily migrate and reuse Fortran code developed on platforms such as IBM mainframes, DEC minicomputers, and UNIX workstations to Intel-based PCs running Windows 95 or Windows NT Workstation 3.51.

Fortran PowerStation 4.0—scheduled to be available in late October—also has extensive support for mixed-language programming with the Visual C++ 4.0 development system, and enables developers to build 32-bit Windows-based applications by combining legacy Fortran code with C/C++ modules. In addition, it can interoperate with other Microsoft development tools such as the Visual Basic programming system and Office for Windows 95.

Fortran PowerStation 4.0 ships with Microsoft Developer Studio, an integrated development environment (IDE) that includes the editor, debugger, browser, profiler, project manager, and books online. This is the same IDE available in Visual C++ 4.0.

In addition, it can interoperate with other Microsoft development tools such as the Visual Basic programming system and Office for Windows 95.

Fortran PowerStation 4.0 fully supports Fortran 90, the new ANSI/ISO approved language standard. Fortran 90 includes support for the earlier Fortran 77 standard and facilitates portability because it standardizes many common extensions to Fortran 77.

Both the Standard and Professional Editions of Fortran PowerStation 4.0 include the 32-bit Fortran compiler and Microsoft Developer Studio. The Professional Edition is available for an estimated retail price of US$799. Licensed users of previous versions as well as Visual C++ 4.0 and Visual Basic 4.0 qualify for a version upgrade price of US$499. The Standard Edition is available for an estimated retail price of US$599 (upgrade price US$299). Reseller prices may vary.

Sunil Alagade is a product manager in the Developer Division.


The Human Factor: The Top 10 Windows 95 User Interface Design Errors

Tandy Trower

September 12, 1995

Now from the home office in Sioux City, Iowa er...Redmond, Washington, here are the top 10 common UI (user interface) design errors to avoid for applications for Windows 95.

10. Properties...crimes

In a previous Human Factor column ("Menu, Please!", Developer Network News, September 1994), I mentioned that an ellipsis (...) should be used only for commands that require further parameters from the user. These are typically gathered by means of a dialog box, such as the Open command on the File menu, in which a user must specify which file to open.

This means that you shouldn't include an ellipsis for every command that results in a window. In a typical application, an Open command includes an ellipsis because the user must specify a file to open. But the Open command on folders in Windows 95 does not, because a user specifies (through selection) the file before selecting the command.

So the fact that you display a window when the user selects a command is not the key criteria for determining whether to include an ellipsis. Neither is whether a user can change something in the resulting window. A Properties command, for example, displays the properties of a selected object, but the command shouldn't be accompanied by an ellipsis. While a user can use the window and change property values, the user doesn't have to specify which object or which property before the command to "display the properties" can be completed. Similarly, commands such as Settings, Preferences, or Help Topics should not include an ellipsis. While all these commands result in a secondary window and may accept some type of user input, the command does not require additional information to process the command, which is typically just to display the current options.

The right test for determining whether to include an ellipsis is, "Does this command require a user to specify or confirm a set of parameters to complete its action?" If yes (for example, Print), use an ellipsis. For commands where the user has already specified the object or parameters before selecting the command (for example, What's This?) or there are no parameters (for example, About), don't include one.

9. Secondary windows appearing in the taskbar

Taskbar entries (excluding the status area) are only for primary windows. The titles of secondary windows such as dialog boxes, property sheets, and message boxes should NEVER have entries in the taskbar.

A primary window serves as an object's main viewer and is characterized by its function and its appearance. It usually results from opening an icon and is generally independent from other windows. A primary window also includes an icon in its title bar, as well as a Minimize (and often a Maximize) button. Secondary windows are dependent, supplemental windows, such as dialog boxes, property sheets, and message boxes.

That said, you may design primary windows that resemble secondary ones. For example, although it is a primary window, the Windows 95 Find File query window may look very much like a dialog box. However, it fits the test for a primary window, so it is included as an entry (button) in the taskbar.

8. Using Ok instead of OK

Always capitalize both letters. This is the correct English spelling. OK?

7. Including icons in title bars of secondary windows

Icons should appear only in the title bar of primary windows. This means icons should not appear in the title bars of dialog boxes, property sheets, or message boxes.

6. Read-only information displayed as static text or disabled text

Read-only text is typically information that you want users to be able to read, select, and copy, but not change. Present it in normal text boxes (typically with an inset border), but with the background matching a secondary window's background. It should also include support for a pop-up menu (with commands such as Copy or Select All).

Static text is intended for labels and descriptive text in a window. The text appears on the surface of a window (without a frame or border, although it can be included in a group box with other controls).

Disabled (engraved or grayed) appearance is intended only to represent items not currently accessible or available. It should not be used when representing read-only information.

5. Using Exit instead of Close

The Exit and Close commands may sometimes seem synonymous, but they are different. Exit implies quitting a process. Close means removing a window.

Don't assume you should include an Exit command for every window in which you include a Close command. A printer window in Windows 95 includes a Close command, but not an Exit, because you don't want to quit any pending print jobs when you close its (queue) window. Similarly, folders don't include an Exit command. As you evolve your software to be data-oriented, Close is the appropriate command. For example, you Open and Close documents or files, but you don't Exit them.

Similarly, be cautious in assuming that Close is always the equivalent of Cancel. Cancel and Close can sometimes have similar results. However, Close can also have results similar to OK when used in a message box where it is the only button. In addition, if there are pending changes in a dialog box, selecting the Close command should prompt the user whether to apply or discard the pending changes.

A final note about using the Close command. Nothing is more confusing to a user than finding a Close button in the body of a dialog box that operates differently from the Close button in the title bar; for example, if the title bar's Close button operates as Cancel, while the Close button inside the window simply removes the window.

4. Incorrect title bar icon and text

What are you supposed to put in the title bar of your primary window? First, you have to define what that window represents. If it is a data object, you should be using the icon you've defined for the data file type and not your application's icon. For example, when you open WordPad or Paint documents, you find the document file's icon in the title bar.

However, for an application that has no data files, you use the application's icon. Similarly, for objects that represent tools that operate on other files, you also use the application's icon. For example, Windows Explorer and Quick View are both special tools that afford secondary views of other objects. So their icons, rather than the data file's icon, appear in the title bar. Similarly, in multiple-document interface (MDI) applications, an application's icon typically appears in the parent window's title bar, while the data file's icon appears in the child window's title bar.

If the Windows flag logo is showing up on your title bar, you haven't defined or set your icon correctly. Windows displays this icon when it doesn't have the correct information for the title bar.

When you have determined the title bar icon, the title text is easy—the first name in the title bar should correspond with the icon you used. In other words, if you decided that a data file icon fits the model for your application, the name of the data file should be adjacent to the icon, optionally followed by the application's name.

3. Supporting multiple instances

Many users may be confused when opening an already open object and getting a new instance. Therefore, it's better to design your application so that it checks to see if an instance (window) is already open and activates that window (which brings it to the top of the z-order) rather than creating another instance.

If your design requires supporting multiple (primary) windows of the same object, consider warning users that an open instance already exists, and give them the choice of either switching to that instance or creating a new one.

2. Failing to include pop-up menus for title bar icons

The inclusion of the icon in the title bar is not intended as a more attractive replacement for the former Windows 3.1 System menu box. It is intended as an access point to the commands of that icon.

While left-clicking the icon brings up the pop-up menu for the window (formerly known as the System menu), your application should support right-clicking the icon to bring up a pop-up menu that contains commands that apply to the object represented by that icon. (Of course, right-clicking anywhere else in the title bar should bring up the pop-up menu for the window.) Typically, this will be a subset of the commands (such as Copy, Create Shortcut, Properties) found on the pop-up menu of the icon that a user opened, but it may also include commands such as Save, which apply to the object's open state but which may not apply to the closed state. For example, your application may not be able to support a Cut command on an open document file, so while the command may appear on the file icon's pop-up menu, you would not include it on the title bar icon's pop-up menu.

And the Number 1 design error to avoid is...failing to register

Last issue's Human Factor column ("Lemme See Your Registration," Developer Network News, July/August 1995) covered the registry, but I want to reiterate that failure to register your file types, primary verbs, OLE information, and icons will certainly make your application's UI seem poorly integrated with Windows. It typically isn't an issue of whether your application will run or not, nor is it intended to enforce some rigid standard. It is a matter of taking advantage of the system's facilities to operate compatibly with the conventions users will expect.

Shameless promotion

Everything I've covered here is detailed in the new UI guide, The Windows Interface Guidelines for Software Design. This latest, greatest set of UI recommendations for designing applications targeted for Windows 95 is now available from Microsoft Press.

Tandy Trower is the director of UI design at Microsoft. Having finished The Windows Interface Guidelines for Software Design, he's hoping to promote the book on Oprah and Letterman soon, but they keep ignoring his calls.


Introducing Microsoft Access for Windows 95

Michael Risse

September 12, 1995

Whether you use Microsoft Access alone or with any of the Microsoft "visual tools," such as the Visual Basic 4.0 programming system, the Visual FoxPro 3.0 database management system, or the Visual C++ 4.0 development system, the Microsoft Access for Windows 95 relational database management system is designed to speed development of your database solutions.

Microsoft Access 95 is 32-bit, multithreaded, adheres to the Windows 95 interface conventions, and takes advantage of many new Windows 95 features. This means that running Microsoft Access 95 requires either the Windows 95 or Windows NT Workstation 3.51 operating system.

This article will focus on five areas that are important to Microsoft Access and visual tool developers.

Microsoft Jet 3.0 database engine

Microsoft Jet 3.0, the database engine at the heart of Microsoft Access 95, will also ship in Visual Basic 4.0, Microsoft Excel 95, and Microsoft Visual C++ 4.0. Because Microsoft Access has a complete set of database creation, design, and optimization tools for Jet, developers can use Microsoft Access to build databases for the other tools that ship Jet. Developers can also use Microsoft Access for ad-hoc report, form, and query creation against databases used in Visual Basic, Visual C++, and Microsoft Excel applications.

The Jet database engine currently provides referential integrity, inner and outer joins, high-performance queries, and an object interface, known as data access objects (DAOs), to all Jet functionality.

Microsoft Access 95 adds DAO methods and properties for new Jet features and enhances the existing set—for example, GetRows (which retrieves rows into an array) and additional security methods. Jet 3.0 is also speedier—thanks to the new 32-bit infrastructure for Jet and open database connectivity (ODBC) data—and has better support for multiuser scenarios. For example, Microsoft Access no longer places all inserts at the end of the database, so there are fewer "lock outs" for users inserting data.

For building Jet databases, Microsoft Access currently provides graphical table design and relationship windows. Microsoft Access 95 adds the following wizards to help design, construct, and optimize Jet databases:

• An Import/Export Wizard that lets you choose data types, indexes, and which columns to import.

• A Table Analyzer Wizard to decipher flat-file data and create a set of related tables with the original data but in a Jet-optimized format.

• A Performance Analyzer Wizard to recommend index, data type, and relationship changes for faster performance.

• A Database Wizard with 20 prebuilt databases that include tables, queries, reports, and forms.

No matter which tool you are using—Microsoft Access 95, Visual C++, Visual Basic, or Microsoft Excel—these wizards for Jet are designed to make your database creation and data importation much easier.

Data replication in Microsoft Access

Replication support in Microsoft Access 95 is "multimaster," which means that data changes can occur at multiple sites. This makes Microsoft Access 95 replication an appropriate tool for load balancing a network database; providing information to occasionally connected users such as "road warriors" who dial in from the field; and distributing application updates. To keep databases in sync with a minimum of network traffic, Microsoft Access replicates changes on a row-by-row basis.

Setting up replication in Microsoft Access 95 is straightforward: create a replicable database (the "design master") and then create copies ("replicas") of the design master. After changes have been made to any of the databases, synchronize the data changes (made in the replicas and design master) or design changes (made to the design master only) between the replicas and design master.

A Conflict Wizard in Microsoft Access handles conflicting changes, and advanced replication schemas can be created with the Replication Manager in the Microsoft Access Developer Toolkit for Windows 95.

Although replication functionality is provided by Jet, only Microsoft Access and Visual Basic provide the DAO interfaces for replication. Therefore, developers using Visual C++ or Microsoft Excel will need one of these products to obtain replication functionality. Furthermore, only Microsoft Access supports Windows 95 Briefcase replication, where a Jet database is made replicable by dragging and dropping it in the Briefcase.

Microsoft Access gains Visual Basic for Applications

Like Microsoft Excel and Microsoft Project, Microsoft Access 95 now has Visual Basic for Applications. This gives developers the ability to share code and expertise across multiple products.

Visual Basic for Applications provides an integrated development environment (IDE) with many new features:

• The editor has a line continuation character, color-coded syntax, multipane code viewing, and optional line-by-line syntax checking.

• Debugging tools include breakpoints, watch variables, an "immediate" window, and a calls window to trace open procedures.

• The object browser enables developers to view the object models of OLE Automation servers and OLE Controls. New WITH...END WITH and FOR EACH...NEXT constructs and advanced parameter support make object handling and property setting easier.

Visual Basic for Applications is a superset of Access Basic, so all Access Basic keywords, constructs, and functions are supported in Visual Basic for Applications. (Note that even though all Access Basic syntax is supported in Visual Basic for Applications, there are some minor changes you may need to make when moving code to 32-bit Windows.)

The addition of Visual Basic for Applications is beneficial not only for Microsoft Access developers but also for those with expertise in Visual Basic for applications from other products, and for developers using Visual Basic who want to share code with Microsoft Access.

Enhanced OLE support for developers

Developers using any of the Microsoft visual tools that support Windows 95 will be able to use 32-bit OLE Controls and OLE Automation to assemble custom solutions quickly from off-the-shelf applications and components.

Microsoft Access 2.0 was an OLE Automation controller—that is, it could control OLE Automation servers with commands such as:

Word6.Insert 'Hello' 'control MS Word

Excel5.Recalc 'control MS Excel

Now, Microsoft Access 95 exposes its functionality to other OLE Automation controllers so that Microsoft Excel, Microsoft Project, Visual Basic, Visual FoxPro, and other OLE Automation controllers can automate Microsoft Access with commands such as:

Access7.CreateTable 'New Issues'

This means that now DAOs and all of Microsoft Access are accessible to programmers from outside the Microsoft Access development environment. In the past DAOs were accessible only from Access Basic (that is, inside Microsoft Access). Benefits of this new OLE support include the ability to create and print Microsoft Access reports from Visual Basic and Microsoft Excel.

Microsoft Access 2.0 was also an early supporter of OLE Controls, the software component model that is best described as an "enhanced" Visual Basic control (VBX). OLE Controls help developers build solutions with prepackaged, ready-to-use components. Examples of OLE Controls include calendar (included in Microsoft Access 95), multimedia, telephony, graphing, communications, and online controls.

Support for OLE Controls enables developers to build (in Visual C++ or Visual Basic) or acquire a library of software components that extend the visual tools line with new functionality.

For developers using Microsoft Access

Although developers can use Microsoft Access to bring database-specific functionality to other Microsoft development tools and applications, many developers create powerful database solutions using only Microsoft Access. This section covers a few new features designed to support these developers. These features include enhancements to the forms design environment, and tools for managing and distributing database solutions.

With forms design, the key is to enable developers to let users "live in forms," since most users prefer the form interface to the less intuitive data table. Therefore, Microsoft Access developers can now create multiple instances of the same form, change control types on the fly (without losing code or properties), and get automatic mapping of table data types to form controls (for example, a Boolean field becomes an option button).

Forms are also more intuitive with Filter By Form, where every form becomes a query that a user can fill in to search for like data, controls tips, multiselect list boxes, and custom right-mouse-click menu options.

Migrating to Microsoft Access 95

Finally, a few thoughts about migrating to Microsoft Access 95. It is possible to run existing databases "as is" in Microsoft Access 95 so they can be shared with Microsoft Access 2.0 users. However, changes cannot be made to the version 2.0 file format in Microsoft Access 95.

Another option is to convert Microsoft Access 2.0 databases to the Microsoft Access 95 file format to take advantage of the new features, new Jet engine, and so on. In this case, Microsoft Access 2.0 users cannot access or attach to data stored in the Microsoft Access 95 file format.

A compromise between leaving the database as is and converting to the new format is the Application Splitter Wizard, which splits databases into two pieces: the data tables, which reside on a network, and the application components (forms, reports, and so on), which reside locally. That way, both Microsoft Access 95 and Microsoft Access 2.0 users can access the data while running different versions of Microsoft Access on their desktop PCs.

Pricing and availability

Microsoft Access 95 (which is version 7.0, to be consistent with the other Microsoft Office 95 applications) is scheduled for availability by the end of November. Major European language versions will be released within 45 days of the U.S. version. Microsoft Access 95 will be sold both as part of the Microsoft Office, Professional Edition and as a stand-alone database product.

The estimated retail price of stand-alone Microsoft Access 95 will be US$339. There will also be an introductory upgrade price of US$109 through December 31, 1995. After that an upgrade will cost US$129.

Microsoft Office 95, Professional Edition will have an estimated retail price of US$599. It will be available at the same time as Windows 95 (it includes a coupon for Microsoft Access 95). Until December 31, 1995, a version upgrade will cost US$309 and a competitive upgrade US$349. After that the upgrade will cost US$399.

In the U.S. and Canada, contact your local reseller. Outside North America, contact a reseller or your local Microsoft subsidiary. More information on the products can also be found on The Microsoft Network at MSN: Go Accessdev, or on the World Wide Web at http://www.microsoft.com/accessdev.

Michael Risse is the lead product manager for Microsoft Access and has shipped three versions of Visual Basic and one of Microsoft Office. He is trying to reacquaint his fly rod with the rivers of Montana.

Microsoft Access Developer Toolkit for Windows 95

Microsoft is also providing tools for distributing and managing Microsoft Access solutions in the Microsoft Access Developer Toolkit (ADT) for Windows 95, one of the hundreds of Microsoft Access support tools that includes books, add-on tools, publications, and conferences. The ADT provides a royalty-free run-time license for distributing solutions to non-Microsoft Access users, an improved Setup Wizard, two-volume Visual Basic for Applications reference, additional OLE Controls, and the Replication Manager for advanced replication schemas and support for replication drop boxes.

The Access Developer Toolkit for Windows 95 is scheduled for availability in November, with an estimated retail price of US$499. Registered ADT 2.0 owners in North America qualify for a US$100 rebate. (A coupon will be in the box.)


Rapid Application Development with Visual FoxPro 3

Rapid Application Development with Visual FoxPro 3.0

Jon Sigler

September 12, 1995

Developers can target Windows, Windows 95, and Windows NT

Microsoft Visual FoxPro 3.0 is a relational database management and development tool that allows developers to create applications on any Windows-based 16-bit or 32-bit operating system—Windows, Windows NT, or Windows 95. Applications created with Visual FoxPro on any of these operating systems will look and run the same on the others without code changes. This means that developers don't have to worry about which operating system their clients are using.

Visual FoxPro complies with the Windows 95 logo requirements, so applications written in Visual FoxPro are eligible for the seal.

Visual FoxPro also gives users direct access to Microsoft BackOffice server components such as SQL Server 6.0, allowing developers to build enterprise-wide, client-server applications.

Object-oriented extensions

Visual FoxPro provides a visual, object-oriented development environment and supports rapid application development through its rich object model, which includes a complete set of base classes and support for inheritance, subclassing, polymorphism, and encapsulation.

Object-oriented programming is based on two fundamental concepts: objects and classes. Instead of thinking about program flow, developers deal with objects—self-contained application components that have private functionality as well as functionality that developers can expose to users. A class is the blueprint of an object, that is, it contains information about how an object should look and behave. In Visual FoxPro 3.0, you can create classes using the following syntax:

DEFINE CLASS Classname1 AS cBaseClass

[[PROTECTED PropertyName1,PropertyName2...]

PropertyName = eExpression...]

[[ADD OBJECT [PROTECTED] ObjectName AS

ClassName [NOINIT]

[WITH cPropertylist]

[[PROTECTED] FUNCTION/PROCEDURE Name

cStatements

[ENDFUNC/ENDPROC]]

ENDDEFINE

You can also create a class visually, using the Class Designer, as discussed below.

The Visual FoxPro object model

The Visual FoxPro 3.0 object model supports features of object-oriented programming such as inheritance, subclassing, encapsulation, and polymorphism.

Inheritance. A newly created object can inherit characteristics (properties and methods) from its parent ("template"), thus eliminating the need for duplicate code. A developer can also override the inherited characteristics to customize an object for specific use. Visual FoxPro 3.0 fully supports inheritance and overrides either syntactically (through code) or visually (through the design interface).

Subclassing. A newly created class can also inherit characteristics from a parent, thus becoming the subclass of its parent class. Subclassing allows users to create libraries of reusable classes with very little or no new code. Subclassing also allows the easy addition of new functionality to a group of objects: A developer simply introduces the functionality once in the parent class, and all derived child classes inherit that functionality automatically.

Encapsulation. Object-oriented programming allows developers to package attributes (properties) and behaviors (methods) together within an object. In Visual FoxPro, you can package information about an object so that the information can be accessed only through specific interfaces. This allows you to hide the details of internal implementation and management from users, while supplying the object itself with all the information it needs to know.

Polymorphism. Visual FoxPro 3.0 supports polymorphism, which allows a specific function to change its behavior, depending on the circumstances. For instance, an arbitrary DRAW method can behave differently, depending on the object (for example, a square or circle) that invokes it. This dynamic binding of functionality allows users to create structured class hierarchies, where the basic skeletons of objects are defined in the base class, and specialized code is defined in the derived subclasses.

Event-driven application development

Traditionally, Xbase has required users to either write their own handlers to process a limited set of events or to rely on READ, a wait state that simulates event handling by the system. With Windows, the number of events users may want to access has increased; consequently, event handling has become more complex.

In Visual FoxPro 3.0, users can still fully devise their own event-handling scheme or rely on READ, but, by default, the system (rather than the users) handles object events. Furthermore, the user can now fully access the standard set of Windows-based events (for example, mouse movements that enable the dragging and dropping of objects). Additionally, the FoxPro language for accessing objects has been updated to adopt the standard syntax object.member (where member can be a property or event), which promotes consistency with other Windows-based, event-driven development environments.

Visual design tools

The FoxPro visual design tools, which are geared toward increasing developer productivity, have been enhanced in version 3.0. These tools include the Project Manager, the Database Designer, the Form Designer, and the Class Designer.

The Project Manager in Visual FoxPro 3.0 combines the functions of the FoxPro 2.6 Catalog Manager and Project Manager. The new Project Manager is the central hub for application development and can be used to organize and manage project files. A project is a collection of files, data, documents, and FoxPro objects that is saved as a file with a .PJX extension.

Project Manager window

The Project Manager organizes items in an outline view that you can expand or collapse. A plus sign (+) appears next to a symbol if the project contains one or more items of that type. You can click the plus sign to expand the list. This allows users to access all files associated with the project very quickly without having to go to another area of Visual FoxPro 3.0. You can also open multiple projects, and drag and drop files between open projects.

You can dock the Project Manager window by dragging it to the top or the bottom of the screen. When it is docked, the Project Manager collapses to display only tabs, thus freeing the desktop for designing database applications.

The Database Designer displays all tables, views, and relationships contained in the database. It allows users to create database schemes graphically by adding tables, then associating those tables graphically by dragging and dropping fields.

The Visual FoxPro 3.0 Database Container file stores all the information about a database, including its tables, local views, remote views, and connections. When a user creates a connection to back-end data, the information is stored within the Database Container. This functionality provides easy access to Microsoft BackOffice (specifically Microsoft SQL Server) without leaving Visual FoxPro.

When relationships are set within the Database Container, they are persistent throughout the entire application. For example, when you use multiple tables for forms and reports, FoxPro creates relationships between the tables automatically, based on the relationships specified in the Database Designer, thus providing an efficient development environment.

Regardless of their complexity, nearly all database applications require the use of forms. In Visual FoxPro 3.0, the Form Designer has been improved to increase ease of use and productivity. For example, you can now align objects easily with the Layout toolbar and access an object's layout properties using the tabbed Properties window. You can bind objects and data easily with the graphical Data Environment Designer. You can create complex data management forms by dragging and dropping fields and controls on the form design surface.

The Form Designer is tightly integrated with the Visual FoxPro 3.0 object model. For example, you can save a group of objects as a class while you are designing a form. The Form Controls toolbar is context sensitive, so you can populate the toolbar visually with a specific user-defined class library. The improvements in the Form Designer are also included in the Class Designer, so users do not have to learn two different interfaces for building forms and classes.

Form Designer

With Visual FoxPro, you can create classes programmatically with the DEFINE CLASS command (as discussed above), or visually with the Class Designer. The Class Designer allows users to create their own properties and methods. When a property or method has been defined, it appears on the property sheet.

The classes created in the Class Designer can be based on FoxPro base classes or on custom classes defined by users. They fully support inheritance, subclassing, polymorphism, and encapsulation.

OLE support, too

Visual FoxPro 3.0 also supports OLE services, which are designed to help developers build custom applications more quickly. For building integrated solutions, for example, Visual FoxPro 3.0 includes OLE Automation, which enables it to programmatically control other business tools such as the Microsoft Office business productivity applications. (See "Using OLE Automation in Visual FoxPro" by Paul Bienick, Developer Network News, July/August 1995.)

Pricing

Visual FoxPro version 3.0 Professional Edition is now available, with an estimated retail price of US$499; an upgrade from previous versions costs an estimated US$299. The Standard Edition has an estimated retail price of US$199 (upgrades US$99). For more information, please call (800) 426-9400 from within the United States or Canada. For price and availability information in other countries, contact your local Microsoft subsidiary.You can also get more information on the World Wide Web at http://www.microsoft.com/foxpro.

Jon Sigler is the lead technical product manager for Microsoft Visual FoxPro. He is responsible for encouraging the product group to include the features and functionality users request.


Visual Basic 4

Visual Basic 4.0 Goes Live: 16-Bit/32-Bit Rapid Application Development

Robert Eineigl and Randy Morgan

September 12, 1995

At last, it can be proclaimed from the Web sites: Visual Basic 4.0 comes to the table and raises the ante again!

The software jocks of Microsoft's Developer Division have given Visual Basic 4.0 full 32-bit performance, 16-bit/32-bit source compatibility, integrated version control, new Windows 95 controls, and the ability to create and use OLE components. Visual Basic 4.0 is now poised to take full advantage of all 32-bit Windows platforms.

For the hardened veteran of too many vaporous claims about software, only hands-on use will provide the acid test. But, we hope this article will open over-caffeinated eyes to some of the cooler capabilities of Visual Basic 4.0. It will also detail remote automation technology, which essentially adds distributed processing (yes, you read that correctly!) to the Visual Basic developer's arsenal.

Three versions

Visual Basic 4.0 comes in three flavors: Standard, Professional, and Enterprise Editions. The Professional Edition adds more custom controls, full programmatic control of the database engine, a new Crystal Reports writer, Windows 95 and Windows NT support, OLE Automation server creation, and client-server connectivity to the feature list of the Standard edition. The Enterprise Edition stacks Microsoft Visual SourceSafe version control, remote data objects/remote data control, and remote automation on top of the Professional Edition. For brevity, this article will assume that you will be using the Enterprise edition.

Enough introduction. On to the feature presentation!

Features

Because a programming language allows creative and unforeseen application of its features, the following list doesn't presume to rank the new capabilities in order of importance:

• Coexistence of 16/32-bit versions. The 16- and 32-bit versions of Visual Basic 4.0 are completely source-code-compatible. Visual Basic 4.0 includes 16- and 32-bit OLE versions of every VBX ever shipped by Microsoft (except the Pen VBX), making porting 16-bit apps to 32-bits a matter of recompiling, aside from API usage.

• Conditional compilation. This allows parallel development on both 16- and 32-bit platforms. The declarations of API calls, for example, can be wrapped in #If Win16 Then #Else #End If syntax. Debug code can also be wrapped to exclude it from the final executable.

• New 32-bit Jet database engine. Visual Basic 4.0 adds many new features to the Jet engine, including enhanced performance, database replication, and full programmatic access to all features.

• Add-ins. The Visual Basic development environment itself has been exposed as an OLE object that can be manipulated programmatically via OLE Automation to enhance its extensibility. Third parties can create CASE tools, add menus, and modify projects with two-way communication between Visual Basic and add-in tools. Best of all, you can write your own add-ins in Visual Basic 4.0.

• Support for resource files. This allows bitmaps, strings, and data to be loaded on demand from the resource file and produces one central file to modify in order to localize an application for international markets.

• Remote Data Objects. Open database connectivity (ODBC)-based remote data objects (RDOs) give developers a programmatic interface for accessing data. Performance-tuned for Microsoft SQL Server 6.0 and Oracle7.x database servers, RDOs offer server-specific features not accessible through the Jet database engine in Visual Basic. RDOs provide full ODBC 2.5 support and require a very small memory footprint because they are simply a thin "wrapper" on the ODBC API. RDOs can return multiple result sets, control server-side cursors, perform asynchronous queries, limit the number of rows returned from a query, set the fatal error threshold, and access underlying ODBC handles.

• Remote data control. The remote data control (RDC) is a new GUI interface for binding data-aware controls to RDOs. This leverages the power of bound controls for client-server development. New data-aware controls—DB Grid, DB List, and DB Combo—accompany the RDC. An OLE Control can now be bound to a data-source control, making it easy to view and edit stored OLE documents. This control can display any OLE document, such as a compound document, bitmap, or AVI video clip, contained in a database.

• Visual source code version control. Visual SourceSafe is provided, fully integrated with the Enterprise Edition's design environment. Development teams can work in concert without having to leave the environment of Visual Basic 4.0. Visual SourceSafe is a source-code control/configuration management system designed to manage multiple releases and promote code reuse while preventing accidental code loss or alteration. Developers employing other Microsoft tools can use it as a central development manager.

• OLE server creation. Visual Basic 4.0 is now the easiest tool to create both in-process and out-of-process OLE servers. An in-process server is a dynamic-link library (DLL) with an OLE wrapper on it. That means it can be browsed with any OLE object browser, and is loaded and run in-process, like a DLL, for best performance. An out-of-process OLE server is an EXE that runs in its own process space but can in turn call in-process servers and DLLs.

OLE servers provide robust, encapsulated, binary reusability. They allow developers to create remotely executable OLE servers, dynamically shareable code modules, and libraries of commonly used forms; perform operations asynchronously (web agents, report generators, and so on); and package business rules, commonly used code libraries, and any legacy code into reusable, programmable OLE Automation servers.

Remote automation technology

Remote automation technology provides the means to perform distributed processing, as promised in the introduction. The Enterprise Edition allows any OLE Automation-enabled client to call out-of-process OLE servers created with Visual Basic 4.0 over a network. These aren't loaded over the net into the calling CPU but rather utilize the remote computer's resources. This capability allows developers to take frequently changing code or business rules (which have traditionally been hard-coded into every client application) and centralize them on a remote server. This provides several advantages:

• Moving code from each client application to a centralized server simplifies application maintenance and reduces administration costs. Remote automation servers can easily be created and debugged on a single computer before deploying them to the network.

• Complex business rules are difficult to create and maintain using the SQL language. By creating a remote automation server and placing it in a three-tier architecture between the client and the server, developers can create and maintain business rules using Visual Basic instead of SQL. They can also take advantage of the source-code control, better debugging, richer math routines, and more powerful control-of-flow syntax of Visual Basic.

• Remote automation allows developers to take advantage of often more powerful server computers and offload large, time-intensive and computationally intensive tasks to remote server computers, or to their neighbor's computer.

• Any OLE Automation client application can easily employ servers using remote automation technology across all major network transports, including TCP/IP (think Internet!), NetBEUI, IPX, and named pipes.

Note that the OLE proxy and OLE stub handle the negotiation between the client and the server transparently. Automation Manager (AUTMGR32.EXE), a tool provided with the Enterprise Edition, must be running on the server to handle the remote procedure calls (RPCs).

Scenarios, scenarios

Now, let's throw out a few possible scenarios. You can probably dream up many more of greater vision; when you do, please think kindly of us!

Scenario 1: Taking stock

You are head of development at a large brokerage firm. (Hey, it's hypothetical; think BIG!) You write an OLE server for your Dual Pentium-based server that accepts raw feeds from a stock quote service. But the volume of data is more than any one broker needs to see in near real-time. So, you set up asynchronous, two-way communication between an individual broker's computer and the server computer. This allows a broker to subscribe to just the feeds she is interested in, freeing her CPU for browsing the pertinent information.

Scenario 2: Hey buddy, can you lend some time?

You manage the IS department at a large mortgage company. Your problem is that you have limited computing resources but a large number of intensive numerical algorithms running on different computers throughout the day. There is idle CPU time available throughout the company but no way to distribute that power to the loan officers who need it.

Your solution is to write an OLE server that knows all the algorithms (in-process), and another that acts as the remote server (out-of-process). These servers are set up on every computer with enough CPU power and RAM to perform the calculations efficiently. When a client needs a calculation done, she merely starts a program on her computer, which calls a single centralized pool manager program remotely. This, in turn, assigns the task to an idle remote server, which calls its local DLL to process the calculation and return the result to the client's computer. Meanwhile, the client is able to use the full power of her CPU locally and is notified when the results are ready.

Creating a simple remote server

Just how easy is it to create a simple remote server?

The explanation of the steps will take more bytes than the code. This simple example obtains the logon name of the user of a remote computer, through a Win32 API call executed on the remote computer.

Phase One: Create the server

Create a new project (UserName) with a default form (Form1). Next, from the File menu, choose Remove File to remove Form1 since we don't need it for the server. From the Insert menu, add a module (Module1) and a class module (clsUserName) to your project. Now place the following code in the General Declarations section of Module1:

Declare Function GetUserName Lib advapi32.dll

Alias "GetUserNameA" (ByVal lpBuffer As

String, nSize As Long) As Long

Sub Main ()

End Sub

The next step is to add the following code to the General Declarations section of clsUserName:

Property Get sUserName() As String

Dim lpBuffer As String * 255

Dim lRet As Long

lRet = GetUserName(lpBuffer, 255)

sUserName = lpBuffer

End Property

In the Properties window for clsUserName, set the following properties:

Property

Value

Instancing

2 - Creatable MultiUse

Public

True

Now, from the Tools menu, choose Options. In the StartMode group of the Project tab, choose OLE Server and SubMain For Startup Form.

You now have a complete, albeit elementary, OLE Automation server. Start the program by choosing Start from the Run menu or by pressing the f5 key and minimizing that instance of Visual Basic.

Phase Two: Create a client to access the server

Start a second copy of Visual Basic. A new project (UseUserName) with a default form (Form1) is created. Add the following code to the appropriate events of the bGetUserName button:

Private Sub bGetUserName_Click()

Dim us As Object

Set us = CreateObject("UserName.clsUserName")

Text1 = us.sUserName

Set us = Nothing

End Sub

Now, start the program by choosing Start from the Run menu or by pressing the F5 key, and then click the bGetUserName button. The logon name should appear in the text box.

Now that you have tested it locally, to execute this remotely, perform the following steps:

1. Compile the server, using Tools/Options/Project to set the option button to OLE Server (vs. Standalone), then File/Make Exe/Options and check the box marked Remote Server Support Files. Close that instance of the Visual Basic 4.0 design environment.

2. Copy the .EXE to another computer (for simplicity, that computer should have Visual Basic 4.0 already installed).

3. Start the Automation Manager (AUTMGR32.EXE) on that remote computer. It must be running for remote automation to succeed.

The OLE server must be registered on the remote server. You can do this by simply executing it once on the server; it registers itself when run. The registry must be set up before remote automation will work.

Security

The remote automation architecture defines two levels of security: access control to the server (and its classes) and data authentication.

RPC data authentication refers to the level of data integrity guaranteed for communication between two computers across the network. For servers running on Windows NT, RPC provides seven levels of data authentication. You must set the authentication level from the client using the Remote Automation Connection Manager (or RACMan), written in Visual Basic 4.0 and provided with the Enterprise Edition.

Run RACMan on the client, select the server (UserName.clsUserName) from the list of OLE classes, and then choose the Server Connection tab. Note that there are three edit fields to satisfy:

Network Address: On Windows NT-based networks, this means simply the friendly computer name. On other networks and depending on which network protocol is used, this may mean an alphanumeric address.

Network Protocol: The protocol you choose for the client must be common to both client and server.

Authentication Level: Set this to Default for this example.

Now choose Remote from RACMan's Register menu and note the icon change. The client is now ready for remote automation. On the server box, since you have registered the OLE server by running it once, all that remains is to set the access control level for the server.

To do this, run RACMan on the server. Choose the Client Access tab and select Allow All Remote Creates, which enables all remote server activations. This is too permissive for real-world applications, but set it to this level just for this example. The registry on the server box is updated immediately.

Now the client running in the environment on your local computer will retrieve the user logon from the remote computer, with no change to the client code.

Pricing and availability

Visual Basic 4.0 is scheduled to be available by mid-September in North America, with an estimated retail price of US$499 for the Professional Edition, and US$999 for the Enterprise Edition. Users of previous versions can upgrade for US$99.95 (Professional) or US$499 (Enterprise). For price and availability information outside North America, contact your local Microsoft subsidiary.

Coming up...

In a future article, we'll go into greater depth on the issues surrounding the creation of OLE servers, both in-process and remote automation servers.

Robert Eineigl works in Microsoft's Information Technology Group. His nocturnal interests include bicycle design, keyboard improvisation, and wildlife serenades with his custom-made trumpet. Randy Morgan is a strategic account engineer at Microsoft. He hikes, bikes, and kayaks, and his friends describe him as an adrenaline junkie.


Visual C++ 4

Visual C++ 4.0 Emphasizes Code Reuse, Integration, and Speed

Jonathan Kagle

September 12, 1995

The Microsoft Visual C++ 4.0 development system provides new tools to ease the reuse and extension of existing code while allowing developers to take advantage of the features of Windows 95.

Visual C++ 4.0 makes large projects more efficient with improved team development capabilities, incremental build technology, and a new way to work with your application structure. It also provides a development environment that integrates with other tools. And it provides OLE Controls, fast data access object (DAO) databases, new C++ language features, and more.

Reuse

Reuse has long been a goal of C++. For C++ programmers, reuse usually means deriving new C++ classes from a preexisting base class. It also means the bigger problem of reusing existing code, C++ classes, user interface elements, prebuilt components, and, most importantly, other developers' knowledge, experience, and programming techniques.

Here's a rundown of some of the features in Visual C++ 4.0 designed to make reuse easier.

Component Gallery

Visual C++ 4.0 includes Component Gallery—an extensible, general-purpose place to store reusable components and add components to an existing project.

Choosing prebuilt components in Component Gallery

In Component Gallery, you can browse through the components available on the system. After selecting a component from the Gallery, you only need to click the Insert button to place the component into your current project. With a click of the mouse, you can store C++ classes and OLE Controls in Component Gallery, and use them as reusable components in almost any Microsoft Foundation Class Library (MFC) application, even those with legacy code

MFC (and the wizards) provide more than 40,000 lines of classes to support OLE containers and servers, OLE Controls, OLE Automation, and more. Visual C++ 4.0 also includes built-in support for creating and using OLE Controls, even in dialog boxes.

The code reuse features of Visual C++ 4.0 provide opportunities for third-party components. More than 50 companies will be providing OLE components that work with Visual C++. Template Graphics Software and Crisis-in-Perspective, for example, will provide new 3-D tools and AppWizards. Crystal Software will ship new MFC add-on class libraries with the new version of Crystal Reports, as well as an OLE Control and an AppWizard to make support of database reporting easier.

Custom AppWizards

In addition to Component Gallery, you can use AppWizards to create projects from scratch. Visual C++ 4.0 includes AppWizards that let you build MFC applications, dynamic-link libraries (DLLs), or OLE Controls. There's even an AppWizard Wizard, which helps you build your own custom AppWizards.

Visual C++ 4.0 and Windows 95

Visual C++ 4.0 runs on Windows 95 and Windows NT 3.51 (Workstation or Server), and allows you to make logo-compliant applications that exploit features of Windows 95.

Visual C++ 4.0 offers full support for the new common controls in Windows 95 and Windows NT 3.51. Multithreading, long filenames, and other Windows 95 features are also supported through MFC 4.0.

The Visual C++ documentation provides step-by-step information on meeting the Windows 95 logo requirements, and the Visual C++ 4.0 AppWizard helps you quickly create an application that meets the Windows 95 logo requirements.

The InstallSHIELD SDK is included with Visual C++ 4.0 to simplify the implementation of compliant setup programs.

Tools work together for efficient development

You no longer need to leave the Visual C++ environment to find a powerful source code editor. The Developer Studio editor provides keystroke macros, remappable keys, multifile search, column select, user-definable syntax highlighting, incremental search, auto indent, soft and hard tabs, splittable panes, and complex pattern matching. And to make the transition easier, BRIEF and Epsilon editor emulations are available through the Options dialog box, along with the traditional Visual C++ key bindings.

The Developer Studio graphical integrated debugger makes tracking down bugs a lot easier. In addition to the interactive disassembly, memory, registers, and call stack windows, there are new multipane variables and watch windows. Additionally, pausing your mouse over your source code will cause a DataTip, which shows the values, to pop up.

The Visual C++ build system has been extended to let you call external tools from an internal makefile. This means you don't need to create an external makefile to work with other compilers, assemblers, or preprocessors. You can insert calls to external tools at any point in the build process. The project system also manages multiple projects from a single workspace.

Other Developer Studio features include an expanded resource editor, with support for OLE Controls; Windows 95 common controls; multiple-language resources; snap-to margins; and the ability to import forms from Visual Basic.

Integration with other tools

The advanced project-management system of Visual C++ contains links to source code control systems. You can have Microsoft Visual SourceSafe or other source code control systems work with the Developer Studio to help developers work better in teams by making code sharing and synchronization easier (see "Visual SourceSafe 4.0 Protects Precious Code" in this issue of Developer Network News). There are also hooks available for other source code control systems.

Microsoft Visual Test, Microsoft Fortran PowerStation, and the Microsoft Development Library all work together within Developer Studio. For example, you can have a Visual Test scenario in the same environment as your C++ source files, making testing faster and easier. The Developer Studio lets you mix Fortran and C++ source files in the same project. And the Development Library viewer integrates seamlessly into the environment; you can even replace the Visual C++ documentation system with the Development Library, so you don't have to swap CDs. (See "Development Library Viewing Engine Merged into Visual Tools Development Environment" in this issue of Developer Network News).

A new way to look at your projects

Visual C++ 4.0 provides a more object-centric view of your C++ projects. With the new ClassView and WizardBar, you can concentrate on your classes. These features let you work with class names and member functions, instead of having to deal with a list of source and header filenames.

ClassView is a tab in the dockable project window that displays the classes and members of your project. This frees you from having to remember which class is in which file and manually opening them. Using an Explorer-like interface, you can jump to, add, or remove classes, member functions, and member variables. Since the ClassView is automatically updated without having to build, you always have an accurate view of your project.

The WizardBar is a tool inspired by the convenient drop-down editor toolbar in Visual Basic. The WizardBar lets you quickly jump to the code that responds to anything from a button click to a WM_TIMER message. You can just as easily add or remove message handlers or other virtual functions derived from MFC classes with the WizardBar.

Faster throughput through incremental technology

Previously, if a source file was modified in any way, the entire file would be recompiled during the next build. Visual C++ 4.0 compiles or links only the parts you change. Incremental compilation means that the compiler will recompile only the changed functions (and functions affected by a change) within an individual source file.

Visual C++ 4.0 includes an improved version of Microsoft's incremental linker. The incremental linker utilizes a technology that permits just those portions of your application that have changed to be relinked, rather than relinking the entire application.

Minimal rebuild permits the Visual C++ build engine to analyze dependencies within a project and to skip compilation of files that it detects are unaffected by a change, even if those files include changed headers.

Support for the latest C++ features

Visual C++ now supports run-time type information (RTTI) and name spaces, two of the latest language features in the C++ draft. It also includes a robust implementation of C++ templates, which can be used with the Hewlett-Packard public domain implementation of the C++ standard template library (STL).

There is also continued support for applications written in ANSI C for Win32, including console applications. The C run-time library now makes better use of system memory and cache, and the source code is included on the CD. A new debug version of the C run-time library automatically tracks memory allocations and frees to help find memory leaks in C and C++ applications.

Visual C++ boosts database speed with DAO, ODBC 2.5

Visual C++ provides two means of data access, each suited to a different need. Both are built into MFC 4.0 and are supported by Component Gallery and the wizards.

First, there's open database connectivity (ODBC), a standard API that allows you to work with data from many databases, including Microsoft SQL Server, Microsoft Visual FoxPro, Microsoft Access, Oracle7, and dBASE. These and other drivers are included with Visual C++, and more are available from third parties.

Visual C++ 4.0 introduces support for DAOs. The new DAO classes for MFC enable you to access the Microsoft Jet database engine directly using MFC.

DAOs use the same direct data access engine as in Microsoft Access 95 and Visual Basic 4.0 to work with a local database or one shared over a network. Because the data access engine is the same, the data formats are identical, so sharing data is easy. The overall DAO architecture of MFC 4.0 is very similar to the database support in Visual Basic, Microsoft Access, and the MFC ODBC classes.

Visual C++: Multiplatform, multilingual

All versions of Visual C++ support both the Win32 API and MFC. In addition to versions that run on Intel platforms, there are also versions that run on MIPS, Alpha AXP, and PowerPC processors, as well as the Visual C++ Cross-Development System for the Macintosh and Power Mac. Microsoft has licensed MFC and the Win32 API to Mainsoft and Bristol Software for products that let you target many major UNIX platforms and VMS with your existing MFC and Win32 API-based source code.

From AppWizard, you can choose from nine languages (English, German, French, Italian, Spanish, Korean, Traditional Chinese, Simplified Chinese, and Japanese) to build applications. You can write applications that run with Unicode or double-byte character set (DBCS).

Coming in October

Visual C++ 4.0 will be available in October. Registered Visual C++ subscribers will get this release sent to them free of charge. The subscription version of Visual C++ 4.0 for Intel processors will have an estimated retail price of US$399. There is also a version available for 0RISC processors and a cross-compiler for the Apple Macintosh.

The Visual C++ subscription provides multiple-platform support for Microsoft Windows 95, Microsoft Windows NT running on Intel platforms, and Windows 3.1 with Win32s. Subscriptions are now available in the United States, Canada, and Europe. Elsewhere, the CD will be available as a stand-alone upgrade through local Microsoft subsidiaries.

If you live in the U.S. or Canada, you can upgrade to the Visual C++ subscription by sending in the upgrade card in the box. If you've lost the card, call (800) 719-5577 to place your order. In Western Europe, contact your local subsidiary.

Jonathan Kagle is a product manager for Visual C++ and Microsoft Visual Test. By night, he fights for justice as Bing Spango, Private Investigator.


Visual SourceSafe 4

Visual SourceSafe 4.0 Protects Precious Code

David Streams

September 12, 1995

New version features integration with Visual Basic 4.0 and Visual C++ 4.0

Code is a precious resource. To protect it, developers need to safeguard files against unauthorized changes and unexpected failures with some system of version control. These systems can vary from gentlemanly agreements about commenting on changes and storing old versions to sophisticated software systems that track changes and histories automatically.

Most of these source control systems work well for individual source files. However, almost all fail to establish relationships between files. This can pose quite a problem in the Windows-based environment, where a single application may consist of multiple executable files and dynamic-link libraries built of many different source files that, in turn, may be reused among many other applications. Today it is as important to manage the relationships between source files as it is to protect the contents of the source files themselves.

New features in Visual SourceSafe 4.0 include integration with the Visual Basic 4.0 and Visual C++ 4.0 development environments, a new Windows 95 Explorer look and feel to the user interface, and updated menus and icons. Visual SourceSafe 4.0 also offers more flexibility with long filename support, customizable columns, drag-and-drop file sharing, accelerator keys, and tab dialog boxes for easy customization.

Visual SourceSafe works with any type of file, including text or binary. Visual SourceSafe is a multiplatform development tool, supporting Windows 95, Windows 3.1, Windows NT, MS-DOS, and Macintosh platforms. Visual SourceSafe for UNIX is also available from Mainsoft Corporation.

To understand the benefits of project-oriented source control, simply compare it to a file-oriented system. A standard version control system (such as the UNIX utility RCS) is essentially a collection of tools that operate on individual files, controlling file access and updates and comparing previous versions. To operate on a group of files, you write a batch file or specify wildcards on the command line.

Visual SourceSafe stores files in a central database on the network, rather than in ordinary MS-DOS directories. Projects viewed through Visual SourceSafe contain all your source files and histories organized into project hierarchies.

When you retrieve a file, Visual SourceSafe marks the file as checked out to you in its database, then allows you to make changes to the file on your computer. When you check the file back in, Visual SourceSafe updates its database and changes the file's access privilege on your computer back to read-only.

So how is this any different from file-oriented source control?

With each change, the Visual SourceSafe database records and tracks project information not available to file-oriented systems. Each time a file is added, modified, shared, moved, or deleted from a project, Visual SourceSafe updates both the file and the project's history. You can use project history to:

• View the status of all files in a specific project and all subordinate projects prior to building.

• Zoom in on a specific file change that might have caused a bug in a build on a certain date.

• Recreate any previous version of an entire application.

• Maintain source files that are shared among many different applications.

• Determine which projects are affected by changing a file that is shared among many different applications.

• Manage client-specific versions of a general application.

Attempting these tasks with file-oriented systems can be incredibly burdensome and frustrating for software developers. Visual SourceSafe project-oriented version control is designed to make all of these tasks more straightforward.

Pricing and availability

Visual SourceSafe is scheduled for availability in October. It will be released in English, German, French, Italian, Spanish, and Japanese versions. The estimated retail price of the full stand-alone version is US$499. Users of SourceSafe version 3.1 can upgrade for an estimated retail price of US$99.95. In the United States and Canada, contact your local reseller. Outside North America, contact your local Microsoft subsidiary.

David Streams is a product manager for Visual SourceSafe.


Ask Dr. GUI #23

(He ordered his MD from the 1918 Sears catalog.)

January 1995

Have a question? Dr. GUI's busy operating schedule won't allow him to answer all questions, but the Good Doctor will answer as many as he can in the next release of the Microsoft Development Library. Send your questions to:

Dr. GUI
Microsoft Developer Network
One Microsoft Way
Redmond, WA 98052-6399

Fax: (206) 936-7329, Attn: Developer Network
Internet: msdn@microsoft.com

Questions in this issue:

Window Irregularity? Using SetWindowRgn

Bad Hair Day: Resetting Windows NT3.5 Auto Logon

Save My Job! Resizing Bitmaps to a Client Window

Is It DDE or DDEAD? Use the OLE Object in Media Player

Yet Another Bad Hair Day: Avoiding Global Variables

Cok Yorgunum. Ne Desem Ki? AutoDucking for Full-Text-Search


 Window Irregularity? Using SetWindowRgn

Dear Dr. GUI:

I'm trying to create an SDI (single-document interface) application that has an irregularly shaped client area in my Windows NT application. After digging through the Developer Network Development Library, I have concluded that this is not possible. However, before I back off from this idea, I would like to know if it would be possible to "fake" it by having a transparent window background. I've been able to have my app initially come up this way (that is, whatever is behind my window is visible through the nonpainted portions of the client area), but when the window is moved the background is not updated. Hence my background always shows the scenery that was behind my app when I started the app. Any ideas?

Confused in Redmond

Dr. GUI replies:

Ugh. Irregularity.

Irregularity is a common problem for humans but a weird problem for windows. In olden times (before the Win32 API), there wasn't an easy way to overcome this problem. However, since you are writing a Windows NT 3.5-based application, you can take advantage of the new SetWindowRgn function. This function (also supported under Windows 95) allows you to set the clipping region for a window including the border. The shape of your region depends upon how you created it. You can create elliptical, polygonal, rectangular, and round regions via calls to the CreateEllipticalRgn, CreatePolygonRgn, CreateRectRgn, and CreateRoundRgn functions. You pass to the creation function the coordinates bounding the region that you wish to set, and the function returns a handle to the region. Once you have the handle to the region, you can pass it to SetWindowRgn.


 Bad Hair Day: Resetting Windows NT3.5 Auto Logon

Have you ever bought a really cool, expensive gadget to do something that you could have done with a 25-cent gadget? But you used the cool, expensive gadget because it was new and, hey, you didn't know about the 25-cent one? Well, that's what about three thousand of you wrote to tell me.

Specifically, I gave a series of detailed steps to disable auto logon in Windows NT when another, easier solution was to hold down the shift key while you click the Logoff button. Now, don't all write to me asking for shirts, because the first one who sent this clever solution to me is the one who got the shirt. This is his letter:

Dear Dr. GUI:

I couldn't help but notice the Dr. GUI question about setting Windows NT auto logon when you've forgotten to give yourself administrative privileges. The same thing happened to me last month; luckily I didn't have to follow all the steps you listed. There appears to be a back door—if you hold down the shift key while logging off, it brings up the logon dialog box instead of doing an auto logon. I never found this documented anywhere, and it may be just a Windows NT 3.5 thing since I haven't tried it with Windows NT 3.1. But it's a lot easier!

Eric


 Save My Job! Resizing Bitmaps to a Client Window

Dear Dr. GUI:

Help me, Dear Doctor! You are my last hope. My boss has been hounding me to get this done as soon as possible or face imminent dismissal from my project! I am trying to simply fit a bitmap to the client area of a window without too much distortion. Seems pretty trivial, but I just can't figure it out. Everything I have tried looks really bad.

Wendy Reynolds
Gig Harbor, Washington

Dr. GUI replies:

<Music> Here I am to save the day...Dr. GUI's on the way <end music>. Don't fear, Wendy, I have exactly what you need. The key to the solution is to maintain the ratio between the original dimensions of the bitmap and the subsequent dimensions of the stretched bitmap, that is, x/y = xnew/ynew. The following code calculates the new x and y dimensions of the bitmap. The xDest and yDest parameters are the extents of the destination rectangle. The xBmp and yBmp parameters are the extents of the original bitmap. The new dimensions are written to the xNew and yNew parameters (pointers to integers).

BOOL WINAPI FitToScreen( int xDest, int yDest, int xBmp, int yBmp, int * xNew,
   int * yNew )
{

   int xDiff, yDiff, xAbs, yAbs, xAdj, yAdj, xWidth, yWidth;

   xDiff = xDest - xBmp;
   yDiff = yDest - yBmp;
   // Negative values for xDiff and yDiff imply that the bitmap
   // is larger than the dimensions of the destination retangle.

   xAbs = abs ( xDiff );
   yAbs = abs ( yDiff );

   if ( xAbs > yAbs )
   {
      xAdj = MulDiv ( xBmp, yDiff, yBmp );
      xWidth = xBmp + xAdj;
      yWidth = yBmp + yDiff;
   }
   else if ( xAbs < yAbs )
   {
      yAdj = MulDiv ( yBmp, xDiff, xBmp );
      xWidth = xBmp + xDiff;
      yWidth = yBmp + yAdj;
   }
   else   // they are the same
   {
      xWidth = xBmp + xDiff;
      yWidth = yBmp + yDiff;
   }

   * xNew = xWidth;
   * yNew = yWidth;

   return ( TRUE );
}


 Is It DDE or DDEAD? Use the OLE Object in Media Player

Dear Dr. GUI:

HELP!!!! I am currently developing multimedia CD-ROMs. What I would like to do is have a button be a DDE link to Media Player, and then the user would have full control over the playing of the file. However, I don't have the server name for Media Player, nor do I know what commands are needed to accomplish this task. If you could help, I would really appreciate it.

Mike Green
New York, New York

Dr. GUI replies:

The preferred way of handling the Media Player is as an OLE object. There is no DDE (dynamic data exchange) support in Media Player, so the way to add DDE is to put a wrapper in Visual Basic around the Media Player using MCI.VBX. This means looking at the samples for DDE and the samples using the MCI (media control interface) control and combining them. You may wish to create your own particular look to the interface. For example:

· using 3-D buttons with pictures of actions

· creating a distinctive background

The picture below shows the default MCI control.

As more and more applications begin to use OLE objects, you should expect to see fewer DDE applications.


 Yet Another Bad Hair Day: Avoiding Global Variables

Dear Dr. GUI:

Could I get an awesome, free Dr. GUI T-shirt if I ask you to re-answer a question for which you gave away a free T-shirt when you didn't seem to hear the question correctly? Take those things out of your ears, man. Boris wasn't asking how to pass parameters to subroutines, but rather between *modules* (Visual Basic synonym for .BAS files)! Although you gave a very nice answer for the former. [See "Is Dr. GUI Qualified?" under "Ask Dr. GUI #19" in the Development Library. —Dr. G]

A minor problem with Visual Basic 3.0 is that you are encouraged to declare global variables in a .BAS file that contains a function for displaying a dialog box in a corresponding .FRM file. In other words: X.FRM wants to call a function in Y.BAS that will run Y.FRM. But Y.BAS can't talk to Y.FRM without declaring globals, which are then visible to everyone.

The question is: What is your favorite way to avoid global variables in that scenario? Thanks in advance, and keep printing the very interesting developer information. I wear X-large.

Scott Zimmerman
San Diego, California

Dr. GUI replies:

I am just not making any headway! Let's revisit yet another "oldie moldy." My favorite way of handling the problems you are talking about is to implement pseudo-object design, which is sometimes called data structures. Most Visual Basic developers use data structures only when it is required for an API call. I tend to use it all the time.

The typical scenario is to create what I call a drop-in component. To create a drop-in component, you define a data structure, say tagFooBar, which will be declared in a module called FooBar.Bas. This FooBar.Bas module will contain only public routines that take tagFooBar as one of the arguments. The other arguments for these public routines must be elementary Visual Basic objects—for example, strings, integers, forms, controls, and objects. There should be no global declaration in this module. If this data structure needs dialog boxes, they are handled by this module exclusively.

If these rules are followed, the code may be dropped into different projects without requiring any code changes to the module. The application declares the number of instances of the data structure needed, and then calls the public routines in FooBar.Bas as needed. The diagram below shows how this was implemented in a forthcoming article in the Microsoft Development Library that explains how you add spell checking to a Visual Basic application.

Now to return to your specific questions on passing data between modules. Consider two arrays of structures, foobarA in BasA and foobarB in BasB. If you wish to pass this data between BasA and BasB, simply call routines in BasB such as the ones shown below:

Sub PutBasA(Arrfoobar() as tagFooBar)
  Redim foobarB(lbound(Arrfoobar) to ubound(Arrfoobar))
  for i%=lbound(Arrfoobar) to ubound(Arrfoobar)
    foobarB(i%)=ArrFoobar(i%)
  next I%
End Sub

Sub GetBasA(Arrfoobar() as tagFooBar)
  Redim ArrfoobarB(lbound(foobarB) to ubound(foobarB))
  for i%=lbound(foobarB) to ubound(foobarB)
    ArrFoobar(i%)=foobarB(i%)
  next I%
End Sub

The second part of your question has both a complex and a simple solution. I will present the simple solution only (because I am a simpleton). If Y.BAS changes a visible or invisible label box, the change event occurs. This change event can then call a function such as GetBasA shown above to obtain the current values in the data structure (I assumed you created a data structure that has all the data in the form). The Y.BAS module could have a public routine called UpdateFrmWithCurrent that changes this label box. The process in the X.BAS module would then be:

GetFrmYData  foobar
foobar.name="Dr.Z"
etc
SetFrmYData foobar
UpdateFrmWithCurrent foobar

If you have multiple instances of a form, you simply add the form as a parameter to the routines. I leave you to add the rest of the code.


 Cok Yorgunum. Ne Desem Ki? AutoDucking for Full-Text-Search

Dear Dr. GUI:

PSS ID Number Q105541 discusses the availability of full-text search of help (hypertext) files for Visual Basic documentation. My application involves the use of a Help file for programming standards for a large shop of RPG/400 programmers using a Windows interface to the AS/400 development environment.

Please share the names and availability of the utilities that Microsoft uses to generate the .IND (index) files for the Help module, and a snapshot of any special codes required with the .RTF draft of the Help.

Since programmers and anyone else will approach a topic differently, the full-text search capacity is the answer to our "where is it indexed now?" dilemma.

R. Patrick Mallory

Dr. GUI replies:

Catchy title, isn't it? And it really is true. Deadlines just drive me up the wall. Patrick, if you can figure out this heading, let me know and I will send you a certificate for a free espresso next time you are at Microsoft.

The .IND files are generated by Multimedia Viewer 1.0, which has been replaced with the Multimedia Viewer 2.0 retail product and the MediaView developer's product. You will find MediaView on the Developer Network Development Platform. The April 1995 issue of the Development Library will include an article and code for AutoDuck, which does what you are suggesting and more. This unsupported tool will take source code from many places and automatically compile it into a full-text-search multimedia title similar to the Development Library CD. The sample source documents used in the demo code include SQL Server scripts, Basic (Visual Basic and Visual Basic for Applications), batch and command files, and MS Mail files.

There are no special codes required for the .IND files, but you must be careful with your browse sequence. If the browse sequence contains group references, they must be declared in the project file. For example:

Admin:00003
User:00003
Dev:0004

would require three declarations in the project file and would result in three books appearing in the Search dialog box.


CompuServe: A Gateway to Internet Resources

July 13, 1995

The Internet provides a wealth of technical resources and information for developers. There is a wide variety of ways to delve into this gold mine of e-mail lists and news groups. One of the most comprehensive is through CompuServe NetLauncher, which offers full access to the Internet using any browser that supports point-to-point protocol (PPP) and to the World Wide Web through SPRY Mosaic.

CompuServe members can download the NetLauncher software free (GO INTERNET). To use NetLauncher, you need to run WinCIM version 1.3 or later, or CompuServe Navigator for Windows. If you are not currently a CompuServe member and would like to explore the Internet through CompuServe, call (800) 524-3388 from within the U.S. or (614) 529-1340 from outside the U.S., and ask for Operator 230.

CompuServe's US$9.95 monthly basic service fee now includes three hours of Internet access per month. An optional "Internet Services Club" offers 20 hours a month for US$24.95. Detailed information on pricing can be found on CompuServe at GO INTERNET.

Usenet news groups

You may want to check out the many developer-related Usenet (Net News) news groups, which are peer-to-peer discussion forums centered on particular areas of interest. In addition, Usenet provides FAQs—lists of frequently asked questions and answers, maintained by third parties. The Microsoft Windows Programmer FAQ contains developer information, and the Microsoft Windows FAQ contains user information. These FAQs are available in either ASCII text or Windows Help file formats.

A sampling of mailing lists on the Net

Here is a sample of developer-related mailing lists on the Internet. (Unlike many of the CompuServe forums monitored by Microsoft Developer Support, none of these peer-to-peer forums are officially supported or monitored by Microsoft.)

CompuServe charges for e-mail received from Internet mailing lists at the same rates as its regular mail services. Comparative information on rate plans is available from GO MAILRATES.

Mailing Lists

To subscribe, e-mail the message:

To post messages to the list, e-mail:

NTDev (Windows NT-based development). Discussions of Windows NT-related developer issues.

E-mail the administrator
at: NTDEV@ATRIA.COM

NTDEV-REQUEST@ATRIA.COM

Windows-NT (Windows NT). General discussions about all aspects of Windows NT in both workstation and server forms.

JOIN Windows-NT <your first name> <your last name>
to: MAILBASE@MAILBASE.AC.UK

WINDOWS-NT@MAILBASE.AC.UK

MS-Back-Office (Microsoft BackOffice). General discussions about all aspects of Microsoft BackOffice products, such as SQL Server, SNA Server, Systems Management Server, and Microsoft Exchange.

JOIN MS-BACK-OFFICE <your first name> <your last name
to: MAILBASE@MAILBASE.AC.UK

MS-BACK-OFFICE
@MAILBASE.AC.UK

LANMan-L (Windows NT Server and LAN Manager). Discussions of user and developer issues regarding Microsoft LAN Manager and related networks, such as Windows NT.

SUBSCRIBE LANMAN-L <your first name> <your last name>
to: LISTSERV@LIST.NIH.GOV

LANMAN-L@LIST.NIH.GOV

WinDev-L (Windows 3.x). Discussions of developer issues regarding products for Microsoft Windows 3.x, including Visual C++.

SUBSCRIBE WINDEV-L
to: LISTSERV@NETCOM.COM

WINDEV-L@NETCOM.COM

MSMail-L (Microsoft Mail). Discussions of user and developer issues regarding Microsoft Mail and related messaging products.

SUBSCRIBE MSMAIL-L <your first name> <your last name>
to: LISTSERV@YALEVM.CIS.YALE.EDU

MSMAIL-L@YALEVM.CIS.YALE.EDU

FoxPro-L (Microsoft FoxPro). Discussions of user and developer issues regarding Microsoft FoxPro and related database products.

SUBSCRIBE FOXPRO-L <your first name> <your last name>
to: LISTSERV@UKANVM.CC.UKANS.EDU

FOXPRO-L
@UKANVM.CC.UKANS.EDU

FoxPro-L (Microsoft FoxPro). Discussions of user and developer issues regarding Microsoft FoxPro and related database products.

JOIN FOXPRO-L
to: FILESERV@POLARBEAR.RANKIN-INLET.NT.CA

FOXPRO-L@POLARBEAR.RANKIN-INLET.NT.CA

OLE (Windows objects). Discussion of developer issues related to Windows objects.

SUBSCRIBE OLE <your first name> <your last name>
to: LISTPROC@MOM.SPK.OLIVETTI.COM

OLE@MOM.SPK.OLIVETTI.COM

VisBas-L (Visual Basic). Discussions of user and developer issues regarding Microsoft Visual Basic and related language products.

SUBSCRIBE VISBAS-L <your first name> <your last name>
to: LISTSERV@TAMVM1.TAMU.EDU

VISBAS-L@TAMVM1.TAMU.EDU

WinHlp-L (Windows Help/Multimedia Viewer Authoring). Discussions on writing Windows Help and Microsoft Multimedia Viewer authoring titles.

SUBSCRIBE WINHLP-L <your first name> <your last name>
to: LISTSERV@ADMIN.HUMBERC.ON.CA

WINHLP-L
@ADMIN.HUMBERC.ON.CA

XLDev (Microsoft Excel). Discussions of developer issues regarding Microsoft Excel.

E-mail the administrator
at: CLAY=XLDEV-ADD@CS.CMU.EDU

CLAY=XLDEV@CS.CMU.EDU

Word-PC (Microsoft Word). Discussions of user and developer issues regarding Microsoft Word and related editing products.

SUBSCRIBE WORD-PC
to: LISTSERV@UFOBI1.UNI-FORST.GWDG.DE

WORD-PC@UFOBI1.UNI- FORST.GWDG.DE

WinSock (Windows Sockets 1.x). Discussions of developer issues regarding Windows Sockets 1.x. This mailing list is cross-posted to the Usenet.comp.os.ms-windows.networking.tcp-ip newsgroup.

SUBSCRIBE WINSOCK <your e-mail address>
to: MAJORDOMO@MAILBAG.INTEL.COM

WINSOCK@MAILBAG.INTEL.COM

WinSock (Windows Sockets 1.x). Discussions of developer issues regarding Windows Sockets 1.x. This mailing list is cross-posted to the Usenet comp.os.ms-windows.programmer.networks newsgroup.

SUBSCRIBE WINSOCK-HACKERS <your e-mail address> to: MAJORDOMO@MAILBAG.INTEL.COM

WINSOCK-HACKERS
@MAILBAG.INTEL.COM

WinSock (Windows Sockets 1.x). Discussions of user issues regarding Windows Sockets 1.x.

SUBSCRIBE WINSOCK-USERS <your e-mail address>
to: MAJORDOMO@MAILBAG.INTEL.COM

WINSOCK-USERS
@MAILBAG.INTEL.COM

WinSock (Windows Sockets 2.0). Discussions of developer issues regarding generic issues for Windows Sockets 2.0.

SUBSCRIBE WINSOCK-2 <your e-mail address>
to: MAJORDOMO@MAILBAG.INTEL.COM

WINSOCK-2@MAILBAG.INTEL.COM

In addition to this general Windows Sockets 2.0 alias, there are numerous other topic-specific mailing lists (TCP/IP, AppleTalk, DECnet, IPX/SPX, OSI, wireless, connection-oriented media (telephony), generic extensions to the WinSock 2.0 API, name resolution issues, OS considerations, and architectural framework issues). For more information on these other specific mailing lists, send e-mail with the message HELP to the same MajorDomo address.

WinSNMP (Windows SNMP). Discussions of developer issues regarding Windows SNMP.

SUBSCRIBE WINSNMP <your e-mail address>
to: MAJORDOMO@MAILBAG.INTEL.COM

WINSNMP@MAILBAG.INTEL.COM

Unicode (Unicode development). Discussions of developer issues regarding the Unicode standard.

E-mail the administrator
at: UNICODE-REQUEST@UNICODE.ORG

UNICODE@UNICODE.ORG

Access-L (Microsoft Access). Discussions of user and developer issues regarding Microsoft Access and related database products.

SUBSCRIBE ACCESS-L <your first name> <your last name>
to: LISTSERV@INDYCMS.IUPUI.EDU

ACCESS-L@INDYCMS.IUPUI.EDU

MS-Access (Microsoft Access). Discussions of user and developer issues regarding Microsoft Access and related database products.

E-mail the administrator
at: MS-ACCESS-REQUEST@EUNET.CO.AT

MS-ACCESS@EUNET.CO.AT

WebServer-NT (Windows NT-based WWW servers). Discussions of user and administrator issues regarding Windows NT-based World Wide Web servers.

SUBSCRIBE WEBSERVER-NT
to: WEBSERVER-NT-REQUEST

WEBSERVER-NT
@MAILSERVE.PROCESS.COM

MAPI-L (MAPI Developers Forum). Discussions of developer issues regarding the Microsoft Messaging API (MAPI), Common Mail Calls (CMC), and related interfaces.

SUBSCRIBE MAPI-L <your first name> <your last name>
to: LISTSERV@SEARN.SUNET.SE

MAPI-L@SEARN.SUNET.SE

James Van Eaton of the Developer Network helped compile this list.


A Continuing Dialog on the Development Library and Platform

Backtalk: A Continuing Dialog on the Development Library and Platform

Melinda Hohlbein

July 13, 1995

You are the master of all that you survey. Now go eat your vegetables, pay those bills on time, clean out that closet, and call your mother.

You get the gist here. Now, having to remember tons of rules and things wouldn't be so bad if they weren't always changing. I expect any day now for the American Foundation for the Revelation of Shocking Food Truths to announce that we should be using expressed dandelion oil for cooking because it is the lowest in saturated fat.

Now truth be told, software development is no different. You've got your OLE, your ODBC, your RDBMS, your SPAM, your...(well, you get the point). These pesky technologies are always changing and sometimes even getting more cool. AND you've got to stay on top of it all to COMPETE SUCCESSFULLY in the programming business.

That's where we come in. When you develop for Windows, there's really only one rule to remember: "Do unto others"—no, wait a minute. It's "Never let 'em see you sweat"—no, that's not quite right either. Ah, yes, THE Golden Rule to know is, "Belong to the Microsoft Developer Network." We'll try to see to it that you have what you need to write your basic, stunning application. We can even help with all that confusing legal mumbo-jumbo such as codum ad libem, codum ad nauseam, and codum chock full o' bugae.

There is one more eensy teensy tiny little rule you need to abide by, which is, of course, SEND US YOUR FEEDBACK. We need your feedback to help us accomplish monumental things, such as increasing the effectiveness of lawn fertilizer. We also rely on your comments (the more candid the better) to help us drive the Developer Network program, so don't sit on your ideas, eh? Now, without further adieu, here's the Developer Network member Q & A, which is the primary purpose of this column (well, it's also an integral part of my raison d'être).

Splitting hairs and CD-ROMs

Ernest Amarath of a city that shall remain nameless faxed us and said he didn't want to be politically incorrect, but were we completely deaf to customers' concerns about receiving too many CD-ROMs with Level 2 membership.

This happens to be a MAJOR change, and believe me when I say that it took us none too few cycles to figure out how to implement it without causing members unbearable pain. We have prevailed. For a detailed discussion of what we're doing to slash and not burn as many CDs as we currently do, let your fingers do the walking to the article "The Shape of Platforms to Come," MSDN_JRGRANT3 where our new BUM (business unit manager, that is), John Rae-Grant, weighs in with a column about our plans.

Note to Ernie: Not deaf, my boy, just careful. We know you guys would flay us if we botched the job.

Development Library browser gets a new name and another face-lift

Eat your heart out, Liz. By the time you read this, your July Development Library may have arrived—and it's going to make your socks roll up and down. It's got an updated browser, renamed InfoViewer (version 2.5 for those of you at home playing the Microsoft version number game along with us). Here are a few of the cool things you can expect to see:

• Copy text as RTF (including graphics—YES!)

• Pop-up menus¾a right-mouse-click away

• Microsoft Office standards (Find is now Query, and so on)

Also, be sure to pop in to Dr. GUI's Espresso Stand for a cup of 'feine and the latest on the Development Library.

Tea for two and T for early renewal too

One Rami Rasanen of Fort Lauderdale, Florida, wrote and asked us what the delay was regarding his T-shirt. He renewed his Developer Network membership early, and by gosh we should have sent him the Dr. GUI T-shirt as promised. He also threatened to stay "buck naked" in protest until the T-shirt arrives.

Frankly, Rami, we don't really want to know about your dressing habits, okay? And sorry about the delay, eh? As it turns out, so many of you renewed early that the T-shirt inventory dried up a little quicker than we expected and so caught us with our pants down, that is, shirts off. We have since finished the new design and produced several truckloads of these awesome shirts, so we won't be running out of inventory any time before the Federal budget is balanced.

Windows 95 updated shipment

Jason S. Short of Orlando, Florida, wrote and asked when the latest build of Windows 95 would ship to Developer Network Level 2 members. He also threw in some colorful metaphors that I'll leave to your imagination.

There's no need for ugliness. The Windows 95 shipment was set to go out in June.

Thanks for tuning in to Backtalk this issue; now I believe your mother is expecting a call. Don't be shy. Send us your comments, suggestions, whines, and moans.

Melinda Hohlbein relies on you to fill her head with crazy notions and wild ideas for improving the Developer Network. Don't disappoint her—she has a large, cranky Doberman.


Deep C++: And the Tips Just Keep On Coming

More Nifty Visual C++ Hints

Rico Mariani

July 13, 1995

In the May/June 1995 issue, I offered "Nine Great Debugging Tips for Visual C++ 2.0." MSDN_DEEPC4_3 It's summer here in Redmond, the fairways look lush and the greens fast, so let's play another nine. As with the last column, while these tips are geared to the Microsoft Visual C++ development system version 2.0, many apply to version 1.0 as well.

Tip 1: Wrap external makefiles for added goodness

The project facility in Visual C++ is actually quite general. You can make it run any command to do your build (it doesn't have to be the NMAKE utility that does the work). So, no matter how tricky your build is, you can make an external makefile that will do it.

Doing this has lots of advantages. The output will be captured in the output window, and you can walk through your errors using F4 or SHIFT+F4. The debugger will know what .EXE to run when you debug, and the browser will know what browser database to use. Many Visual C++ settings are remembered on a per-project basis, so you can have custom options for the project if you wrap it. To create the external makefile, just use the File menu's Open command on the primary file that does the build (usually a makefile) and select Open As Makefile from the list at the bottom right.

Tip 2: Change compile flags for more than one file at a time

One of the most under-used features in the project system is multiple selection in the tree control of the project settings dialog box. By selecting multiple files you can see what flags they have in common, and you can change flags for them all at once. This works even across groups or targets—selecting a group or target node in the tree is the same as selecting all the files in the group or target. This is a great way to see exactly which flags change from one target to another.

Tip 3: There are hidden goodies in the project system user interface

The project system is for more than just building. You can double-click resource files to open the appropriate resource editor, drag and drop files from File Manager to add them to the project, and even add random non-source files to the project and use the project system to launch the associated application. Very handy for updating design documents (you do have design documents, don't you?).

Tip 4: The text editor is way cool

The much-maligned Visual C++ text editor has actually gotten a whole lot better. Here's the Top 10 things you probably didn't know the Visual C++ editor can do.

10. CTRL+ALT+T makes your tab characters visible.

9. SHIFT+ESC closes the active dockable window (Output, Watch, Locals, and so on).

8. CTRL+F3 finds the next occurrence of the current word.

7. CTRL+M finds the matching parenthesis.

6. CTRL+> and CTRL+< find the next/previous #ifdef, #else, or #endif.

5. CTRL+SHIFT+R starts/stops macro recording.

4. CTRL+SHIFT+P plays the recorded macro.

3. A right-click on #include lines can open the included file if you choose that option.

2. TAB or SHIFT+TAB indents or unindents selected lines (when the selection spans a line).

1. Holding down the ALT key lets you select columns by dragging.

Tip 5: Sometimes resources just aren't the same

You can cause resources to be compiled conditionally by using "magic" alternate IDs for them. For instance, if you want one version of your Foo dialog box for debug and another one for other builds, you would do so by creating resources for IDD_FOO and IDD_FOO$(DEBUG). The resource editors use this trick to provide Macintosh-specific versions of dialog boxes in the cross-platform version of the product, but you can do so whenever you need.

Tip 6: ClassWizard is just a CTRL+DOUBLE-CLICK away

You can do the normal ClassWizard operation on any dialog control just by pressing the CTRL key and double-clicking the dialog control. If the control is a button, a click handler will be added and you'll be in position to type in the code; otherwise, you are set to add a suitable member variable. This is particularly useful for data-aware controls, where you have to bind the control to a field in your data table.

Tip 7: The bitmap editor has a won't-quit keyboard interface

Almost all of the editing features are on some key or another (there's a handy table in the documentation—in fact, there are keyboard mapping tables for just about all of the features you might use a lot). What's really interesting is that some keys are best used while you're in the middle of a drag operation.

For instance, suppose you're trying to draw a line from one point to another. You might zoom in to get a good look at the starting point, but now you're stuck in zoom mode, since you're in the middle of dragging, right? Wrong. You can press the M key (M is for Magnify) in the middle of dragging to unzoom, then get close to the endpoint and press M again for precise placement. Another favorite of mine is CTRL+B, which turns the current selection into a brush you can draw with. This has dozens of useful applications, not the least of which is making copies of those three-dimensional lines that give an engraved look but that are quite tedious to draw over and over. Check out the key bindings; if you use this editor at all, you'll find them very handy.

Tip 8: Easter eggs—AKA handy undocumented features

Everything I've mentioned already is somewhere in the documentation, but here are a couple of things that didn't make it into the official features list.

Start Visual C++ with the msvc -p <pid> command-line arguments, and the integrated development environment (IDE) will attach itself to the specified process ID for debugging. This is another flavor of Just-In-Time debugging, but the program doesn't have to fault before you can use it. Don't forget that the program will still be running when you do this, so you'll probably have to choose Break from the Debug menu (or you can set breakpoints).

Visual C++ also has a hidden command switch, bppassc:yes, that enables the hidden pass count field on the breakpoint dialog. CodeView users will remember that this feature lets you stop after a breakpoint has been hit a certain number of times. A handy trick that leverages this feature is to set the skip count to something very high (such as 10,000), then see how many times your breakpoint was actually hit before the event of interest (usually a crash). Repeat the scenario, setting the breakpoint count one smaller than was reported. This technique is sometimes the only way to see what went wrong in a frequently called function ("Who'da thunk my code would fail on the 7139th invocation?").

The syntax coloring feature in Visual C++ also supports a set of custom keywords. Just put the words you want highlighted in a file called USERTYPE.DAT in the same directory in which you keep MSVC.EXE; these words will be highlighted in the custom color.

Tip 9: Credit where it's due

To see the credits for Visual C++ 2.0, copy the MSVCCRD.DLL file from the product CD to the same directory in which you keep MSVC.EXE. Then CTRL+DOUBLE-CLICK the picture in the About box. It dismisses itself very easily, so you might have to try more than once to get it to stay up.

Rico Mariani has worked on Microsoft development tools since 1988. This article is based on a talk he gave at SD 95. If you couldn't tell, he recently took up golf.


Extending the Windows 95 Shell

Nancy Winnick Cluts

July 13, 1995

The Windows 95 shell is extensible. You can access tools that manipulate objects in the shell name space, and you can browse through the file system and networks.

All shell extensions are implemented as Component Object Model (COM) objects and reside in dynamic-link libraries (DLLs). Once you grasp the basics of how to implement COM objects, the additional information you need to understand to implement a shell extension should be fairly simple.

The Windows 95 shell supports seven types of shell extensions (referred to as handlers):

• Context menu handlers. Add menu items to the context menu for a particular file object. The context menu is displayed when a user clicks a file object with the alternate (usually the right) mouse button. Context menu handlers implement the IContextMenu and IShellExtInit interfaces.

• Drag-and-drop handlers. Context menu handlers that are accessed when a user drops an object after dragging it to a new location. Drag-and-drop handlers implement the IContextMenu and IShellExtInit interfaces. The only difference between a context menu handler and a drag-and-drop handler is the way it is registered in the registration database.

• Icon handlers. Add instance-specific icons for file objects or add icons for specific file classes. Icon handlers implement the IExtractIcon and IPersistFile interfaces.

• Property sheet handlers. Add pages to the property sheet dialog box the shell displays for a file object. Property sheet handlers implement the IShellPropSheetExt and IShellExtInit interfaces.

• Copy hook handlers. Prevent a folder or printer object from being copied, moved, deleted, or renamed. Copy hook handlers implement the ICopyHook interface.

• Drop target handler. Controls the action that occurs when the shell drops objects on other objects. Drop target handlers implement the IDropTarget and IPersistFile interfaces.

• Data object handler. Supplies the object when files are being dragged and dropped or copied and pasted. Data object handlers implement the IDataObject and IPersistFile interfaces.

Register now

Like all COM objects, shell extensions must be registered in the registration database, or they won't work. Each extension must register its class ID (CLSID) under HKEY_CLASSES_ROOT\CLSID in the registry. Within this key, the extension adds an InProcServer32 key that gives the location of the extension's DLL. The first line in the sample below registers the CLSID of a property sheet extension called NancyPropSheet. The second line specifies the location of the DLL containing the extension and the threading model.

[HKEY_CLASSES_ROOT\CLSID\{771a9da0-731a-11ce-993c-00aa004adb6c}]

@="NancyPropSheet"

[HKEY_CLASSES_ROOT\CLSID\{771a9da0-731a-11ce-993c-00aa004adb6c}\InprocServer32]

@="c:\\windows\\system\\propext.dll"

"ThreadingModel"="Apartment"

Your shell extension must also be registered under the shellex key, which contains the information the shell uses to associate a shell extension with a file type. You can map your shell extension to a particular class of file (based upon the file extension), or you can specify that the shell extension is valid for files of all types. In the property sheet extension sample above, the property sheet was registered specifically for NWCFile as follows:

[HKEY_CLASSES_ROOT\.NWC]

@="NWCFile"

[HKEY_CLASSES_ROOT\NWCFile]

@="Shell Extension file"

[HKEY_CLASSES_ROOT\NWCFile\shellex\PropertySheetHandlers]

@="NWCPage"

[HKEY_CLASSES_ROOT\NWCFile\shellex\PropertySheetHandlers\NWCPage]

@= "{771a9da0-731a-11ce-993c-00aa004adb6c}"

Now say you want all files to reap the benefits of your special property page. To do this, you specify '*' after HKEY_CLASSES_ROOT as seen in the following example:

[HKEY_CLASSES_ROOT\*\shellex\PropertySheetHandlers]

@="NWCPage"

[HKEY_CLASSES_ROOT\*\shellex\PropertySheetHandlers\NWCPage]

@= "{771a9da0-731a-11ce-993c-00aa004adb6c}"

Initial impressions

Besides registration in the registration database, shell extensions share the way in which they are initialized. The shell uses two interfaces to initialize instances of shell extensions: IShellExtInit and IPersistFile.

The IShellExtInit interface is used to initialize context menu handlers, drag-and-drop handlers, and property sheet handlers, while IPersistFile is employed to initialize instances of icon handlers, data object handlers, and drop target handlers. (Copy hook handlers don't use the IShellExtInit or IPersistFile interface.)

After implementing the initialization interface for your shell extension, you need to implement the actual interface for the particular shell extension you are writing. For example, if you are writing a property sheet extension, you will need to implement the IShellPropSheetExt interface.

Debugging shell extensions

When your shell extension is written and registered, what do you do if it doesn't work? It's not like most applications, where you can simply include DebugBreak calls in your code or run the Visual C++ development system in debug mode, set some breakpoints, and go.

Because shell extensions are loaded at the startup of the Explorer, you have to find a way to start the Explorer without loading all of its DLLs. Here's how:

1. Go into your project settings and, under the Debug tab, type the path to EXPLORER.EXE in the Executable For Debug Session edit box.

2. Close all applications you are running, and turn off your computer.

3. Restart Windows 95 and Visual C++, loading your shell extension.

4. Click the Start button and choose Shutdown.

5. Now, hold down the CTRL+ALT+SHIFT keys and simultaneously click No. (Sounds a bit like playing Twister, doesn't it?)

6. The desktop will go blank and your heart will start palpitating, but don't worry. Pressing ALT+TAB will get you to your instance of Visual C++.

7. At this point you are ready to debug. Set your breakpoints and go.

If you want to be able to force the shell to unload DLLs very quickly so you don't need to exit it to debug your shell extension, you can do this through a setting in the registry. Under HKEY_LOCAL_ MACHINE\SOFTWARE\Microsoft\Windows\ CurrentVersion\Explorer, add the AlwaysUnloadDll key and set its value to a number (I set it to 1 because that's the kind of gal I am). Adding this key sets the time-out value for DLLs to a very small value.

Shell extensions and Windows NT

You may wonder whether your shell extension will run on the Windows NT operating system. Windows 95 shell extensions can work on Windows NT 3.51. This version gives a user the option of running Windows NT 3.51 with the Windows 95 shell. To do so, however, there is one additional step that your application must take in its setup process and registration.

For the Windows NT shell to recognize and run a shell extension, the handler's CLSID must also be listed under a new registry key (in addition to the registry entries you need to make for Windows 95) that contains a list of the handlers approved for the shell to run. By default, this key's access control permissions allow only someone with administrator privileges to modify the list. The CLSID must be registered under Windows NT at the following location:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
Shell Extensions\Approved

To register the extension, a "named value" should be added to the Approved key. The name of the value must be the string form of the CLSID that can be obtained through the StringFromCLSID function.

For example, to register the property sheet extension shown above, you can add the following line to your registration file:

[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\

Approved\{771a9da0-731a-11ce-993c-00aa004adb6c}] @="NancyPropSheet"

Security questions

If you haven't written applications for Windows NT, it may seem odd that your setup application may not be able to write to this key. The ability to write to the key depends on the access privileges of the person installing the application. The setup application should attempt to open the key described above, requesting the KEY_SET_VALUE permission. If it succeeds, the new CLSID can be added to fully register the corresponding shell extension.

If the request fails due to a security violation, the user installing the application does not have permission to register new shell extensions. In this case, the setup application might warn the user that some application features will not be available unless an administrator turns them on (by installing the application, or by writing the registry keys directly). Or, if the shell extension is crucial to the application's functioning, the setup application might cause the installation to fail completely, notifying the user that the program must be installed by an administrator.

The following sample code demonstrates how an application can register its shell extension under Windows NT:

// First, attempt to open the registry key where approved extensions are listed.

long err;

HKEY hkApproved;

err = RegOpenKeyEx(

HKEY_LOCAL_MACHINE,

"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",

0,

KEY_SET_VALUE,

&hkApproved);

if (err == ERROR_ACCESS_DENIED)

{

// The user does not have permissions to add a new value to this key.

.

.

.

}

else if (err == ERROR_FILE_NOT_FOUND)

{

// The key does not exist. This should only happen if setup is running on

// Windows 95 instead of Windows NT, or if you are installing on an older

// version of either operating system that does not have the Win95 UI.

.

.

.

}

else if (err != ERROR_SUCCESS)

{

// Some other problem...

}

else

{

// Assume that lpstrProgID contains our ProgID string.

LPSTR lpstrProgID = "My Bogus Class";

// Assume that clsidExtension contains the CLSID struct. The code below creates

// a string from this CLSID. If a string version of the CLSID is already handy,

// skip this code.

CLSID clsidExtension = {0x11111111, 0x1111, 0x1111, 0x11, 0x11, 0x11, 0x11,

0x11, 0x11, 0x11, 0x11};

HRESULT hr;

LPOLESTR lpolestrCLSID;

CHAR rgchCLSID[40];

CoInitialize(NULL);

hr = StringFromCLSID(clsidExtension, &lpolestrCLSID);

// StringFromCLSID returns a Unicode string, so convert to ANSI for calling the

// registry. Note that on Windows NT you can call the Unicode version of the

// registry API instead.

WideCharToMultiByte(CP_ACP, 0, lpolestrCLSID, -1, rgchCLSID, 40, NULL, NULL);

CoTaskMemFree(lpolestrCLSID);

CoUninitialize();

// Now add the new value to the registry.

err = RegSetValueEx(

hkApproved,

rgchCLSID,

0,

REG_SZ,

(const BYTE *)lpstrProgID,

strlen(lpstrProgID));

// Finally, close the key.

err = RegCloseKey(hkApprovedt);

That's all there is to it. For more detailed information about how to implement the different shell extensions, consult the Microsoft Development Library. Some sample code is also available in the merged Win32 Software Development Kit.

Nancy Winnick Cluts, a Developer Network writer, retired from a highly successful career as an international super-model to write Programming the Windows 95 User Interface (Microsoft Press, August 1995).


The Human Factor

The Human Factor: Lemme See Your Registration

Tandy Trower

July 13, 1995

No, this month's column doesn't concern sending in the registration card for the latest Microsoft product you bought. It's about using the registry in Windows 95 to make the most of integrating your application with the system.

You may be wondering why I cover this in a column dedicated to user interface (UI) design. My answer is: Your application's UI will be severely affected if you ignore the registry.

Watz da "registry"?

The registry is a special repository supplied by the system that serves as a configuration database for user, application, and computer-specific information. For example, the system uses this information to determine which icons to display on the desktop and in folders.

The registry has a hierarchical structure; each node in the tree is a key. Each key can have a set of values. Each value entry is composed of three parts: the name of the key, its data type, and the value itself.

When your application is installed, information about it should be stored in the registry. Info can be added to the registry either by using registry APIs or by creating a registry (.REG) file and then using the Registry Editor. A registry file is essentially a text file containing entries following a specified format.

Registering state information

Washington: capital—Olympia; flower—rhododendron; bird—oops, wrong kind of state information.

Ideally, when a user reopens an object (file), it returns to the state in which the user last left it. Windows 95 helps you support this important concept, called "persistence of state."

There are two major keys in the registry for this purpose: HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER. Store machine-specific information under HKEY_LOCAL_MACHINE and user-specific information under HKEY_CURRENT_USER.

Under the Software subkey, you can add your own keys for storing information that you formerly stored in .INI files. Though the Windows 95 operating system supports these for backward compatibility, using .INI files is not recommended. The registry is more flexible and allows the system to track this information better should a user update or move your application's files.

You can also use the two major keys to restore your application's state. Let's say when the user starts up Windows, you'd like to restore any windows open at shutdown as the system does for folders. To do this when a user shuts down the system, design your application to store its state under its registered key entries and then create a value entry for the RunOnce subkey under HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion.

Use your application's name in defining the value name for the entry and assign it to an appropriate command-line string for your application. For example:

WordPad Document 1 = C:\Program Files\

WordPad.exe Letter to Dr. Gui /Restore

The precise syntax here is really up to you. When a user restarts Windows, the system will run your command string and the application can restore its state.

Finding the path

Rather than jam your application's files into Windows directories, you can now place them in a more logical location, and the system can still find them. For example, you register the path where you locate your executable (.EXE) files as well as dynamic-link library (DLL) files by using the AppPaths subkey under HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion. Add a subkey using your application executable filename and set its default value to the path for your .EXE file. Add an additional value named Path for this subkey, and set its value to the path of your DLLs. The system will automatically update the path for these entries if a user moves or renames the application's executable file using the standard system UI.

If you have a DLL that will be shared systemwide among many applications, you should place it in the System directory created by Windows and register its filename as a value for the SharedDLLs subkey.

What's your type?

The most important entries you supply for the registry are your application's file types. These tell the system which icon to display and which application to run when a user opens a specific data file. If a file type is not registered, the system substitutes a generic icon and lists its type as Unknown, with the result being that a user won't be able to double-click its icon to open it.

To register the file types supported by your application, include information under HKEY_CLASSES_ROOT, another major key in the registry. For each extension, you need to create an extension subkey and set its default value to an application identifier string (also known as the programmatic identifier, or Prog ID to you OLE jockeys). Then, using the same string, create another subkey and set its value to the type name (also known as the MainUserTypeName). The type name is the user-readable name of the file type (or class name). You'll typically want to include your company name, product name, and data type. As an option, you can also include a version number. For OLE purposes, you should also register a short type name. (See the OLE documentation for more details.)

Under this application identifier subkey, add a DefaultIcon subkey and set its value to the path of the file that contains the icon for the type. This can be an icon you include in the resources of your .EXE file or in a separate file, such as a .DLL, an .ICO, or a .BMP. If you use an .EXE file, you need to include the index value that corresponds to the icon within the file. A positive number represents the icon's position in the file. A negative number corresponds to the inverse of the resource ID number for the icon. The system always uses the first icon resource in an .EXE file to determine which icon to display for that executable file.

Design your application's file type icons to be related to, but distinctly different from, the application's icon. Include the following sizes: 16x16 (16 color), 32x32 (16 color), and 48x48 (256 color).

Yes, that's right, the system now supports a new, larger icon size, intended for high-performance, high-resolution machines. Also, all icon sizes can be supported in 256 colors. However, greater color depth also consumes more system resources. These sizes and color resolutions were designed to provide appropriate support across a wide variety of systems.

Adding commands

As a good container, the system automatically includes a number of commands for all types. These commands appear on the menus (drop-down and pop-up) of icons of all file types. For example, the system automatically provides Cut, Copy, Paste, Create Shortcut, Delete, Rename, and Properties commands.

However, you have to register other commands as appropriate, such as Open, Play, and Print, to activate the files of your type. To do so, add a Shell subkey under your application identifier subkey. Under it, register a subkey with the name of the operation, or verb, and set its value to the name you want to appear in menus.

The verb name itself should be a language-independent name of the command. However, its value must be localized for the specific version of Windows you install on. In U.S. and English versions, these entries may be the same; for example, Analyze = &Analyze. (The ampersand indicates the mnemonic access character that appears underlined in the menu.)

Then add a subkey named Command and set its value to the command-line string that should be executed to support that command (C:\Program Files\Stock Analysis\Stock.exe /A).

You can also support dynamic data exchange (DDE) execution of the command by including a ddeexec subkey under the verb subkey and setting its value to a DDE command string. Under the ddeexec subkey, you'll need to include Application and Topic subkeys and set their values to the appropriate DDE application name and DDE topic name.

If files of your registered type are printed, you'll want to include Print verb entries. A Print verb subkey displays the Print command on the menu for the file. Including a PrintTo subkey allows the user to drag and drop the file onto a printer icon to have it printed. When supporting printing for your file types, consider providing a command-line switch that allows the file to be printed without bringing up the entire application interface. It is still perfectly appropriate to provide a message box indicating progress of the process, such as "Printing page m of n on printer name."

You can register multiple verbs for your file types to support different operations. To define their order in the menu, include the verb names, separated by commas, as the value for the Shell subkey. The first entry will be set as the default command for the object (which gets executed when the user double-clicks).

Because each verb entry can have a different command line, you can have different executable files handle different operations. You can even register commands for file types that aren't your own.

In the beginning...

Windows 95 has a nifty feature that allows the user to create new files of a specific type without having to invoke the application. For example, the desktop and folders support a New command that provides a list of the file types that can be created. To support this feature, you add an application identifier subkey under your extension subkey. (Don't confuse this with the application identifier subkey mentioned above. This one is UNDER the extension subkey.) Under this subkey add a ShellNew subkey. This subkey can be set to one of four values:

Value name

Value

Result

Nullfile

""

Creates a null file of this type.

Data

binary data

Creates a new file containing the binary data.

Filename

path

Creates a new file by copying the specified file.

Command

filename

Executes the command, runs the file.

You can use the Command value to handle the file creation yourself.

And there's more...

The registry also allows you to register special handlers to extend the shell's basic functionality for adding commands, supporting drag and drop, and adding property sheet pages. It also allows you to include support for the Windows 95 QuickView application, which allows users to view files quickly without having to activate their host application's special functions.

You can also register sound events so the user can use the system's UI to assign sounds to those events. And, of course, if you support OLE, you use the registry to store important details. But such details get into the realm of Dr. GUI. Go bug him or other Developer Network pundits for this stuff, or check it out yourself in the new, merged Win32 Software Development Kit docs.

Tandy Trower is the director of UI design at Microsoft and keeper of the sacred scrolls known as the Windows Interface Guidelines for Software Design.


Look What’s Talking: SDK to Enable Speech in Apps for Windows 95 and Windows NT

Look What's Talking: SDK to Enable Speech in Apps for Windows 95 and Windows NT

Mike Rozak and Jerry Drain

July 13, 1995

Computers that talk have always been a fascinating element of science fiction. Verbal communication makes computers appear smarter, and thus seems to go hand-in-hand with artificial intelligence.

But speech is no longer simply the stuff of science fiction. Not only is speech now available without special hardware and software, but it is coming to the Windows platform—and will very shortly be easy to implement into your Win32-based applications.

Microsoft is working with independent software vendors (ISVs) who provide speech engines, and by the end of 1995 will release a Speech software development kit (SDK). The Speech SDK will provide a set of APIs that will allow developers to enable speech functionality in their applications for the Windows 95 and Windows NT operating systems. With all of this coming down the pike, now is a good time to look at how speech might apply to your application.

Speak to me

Speech should provide a more powerful and intuitive method for interacting with a system than today's mice, keyboards, touch pads, pens, or other devices. Two parts of speech make an application interactive: text-to-speech and speech recognition.

While these technologies are still limited, they can solve a number of different user-interface problems encountered by applications.

Text-to-speech

Text-to-speech synthesizes speech from ANSI or Unicode text, allowing a Windows-based PC to talk to a user. This has obvious advantages: The system can give you information any time you wish—whether or not you are looking at it. It is beneficial to the vision-impaired, when you are multitasking and may be too busy to look at the screen, or when the screen is off. It's also convenient: The computer can notify you audibly of noncritical events—"Printing has completed"—instead of providing a pop-up that you have to dismiss by clicking the OK button.

Text-to-speech is also useful with dynamic text. A good example of this is providing the time of day. In this case, storing all the possible concatenations of numbers to tell the time in a .WAV file would be incredibly expensive.

Text-to-speech has other advantages as well:

Storage: Data in a text format takes up far less storage than even compressed .WAV files.

Speaking unknown text: If the application needs to play speech but doesn't know ahead of time what it will be (such as the user's name), or if it's impossible to record all of the combinations (such as numbers), then the application must use text-to-speech.

Data verification or grammar checking: When the information is read back, a user can easily hear typing mistakes in numbers, names, and words. Likewise, the eye is used to glossing over misspellings and short words. Grammatical mistakes become more obvious if the text is read back.

Notification: Some applications have to notify the user of asynchronous events. Rather than bringing up the message box and making it active (which can interfere with typing), an application can have text-to-speech read the notification. The message box can still be instantiated without being activated, just in case the user doesn't hear the notification.

Word pronunciation: Although text-to-speech doesn't sound great, it's understandable. Rather than writing a word pronunciation in text (for example: "knowledge" = "now-lej"), just have the computer speak it.

Access over the telephone: With the arrival of voice modems in more and more PCs, applications will start providing "phone-based" UIs. For example, a user can call up the computer, which then allows him to look up his schedule, address book, and so on, all over the phone.

Long-distance notification: Text-to-speech can be heard in other rooms of the house. For example, a phone application can look at Caller ID when a call comes in and speak out, "You have a phone call from Fred Smith."

Speech recognition

Speech recognition enables users to speak to a computer, freeing them from keyboards and mice and helping to streamline the interactive process. For example, saying "Yes," "No," "Cancel," or "Send mail to Fred" is often easier or faster than using the mouse to click the buttons. In a more complicated example, it's much easier to say "Print the current page" than to navigate menus and dialog boxes.

Current speech recognition technology can be divided into two categories:

• Command and control: The user can speak one command from a list of several hundred commands. A command can include "lists" or numbers, such as "Send mail to <name>" or "Set the time to <time>." Unfortunately, the user must speak the command exactly as written. He/she cannot say, "Change the time to <time>."

• Dictation: The computer transcribes whatever the user says. To work on ordinary machines, most dictation systems require the speaker to pause between words.

An application can use speech recognition to remedy a range of UI limitations:

Fast access to complex features: A number of applications have frequently used features that are difficult to present or control with a GUI. Often these features can be more easily accessed by speech recognition.

Magic keystrokes: A lot of applications have overloaded the keyboard with not only text entry features but also commands. Voice commands can make life easier for a user because they are easier to memorize. Speech can also be used to activate macros, avoiding the need to come up with and memorize magic keystrokes.

Global commands: Speech can be used when an application wants to have an input hook that is always active, even when that application doesn't have keyboard focus. If the application uses a keyboard hook, it's likely that another application is already using the chosen key, causing conflicts. For example, this allows a user to make a phone call even when the phone isn't the active application.

Form entry: Applications can use speech recognition for form entry, both for selecting elements from a list and for entering numbers. Because speech can have so many commands active at once, it can be listening for all possible values for all the fields at once, and can place data in the proper field.

Access over the telephone: With the arrival of voice modems in more and more PCs, applications will start providing "phone-based" UIs. Speech recognition is a much better interface than maneuvering through menus with touch-tones.

Accessibility: Speech recognition aids people who are poor typists or who cannot use the keyboard or mouse effectively.

Mouse overload: Some applications (especially CAD systems) drag, drop, and select objects with the mouse. For more complex actions, a user either has to memorize a magic keystroke (which may not have the information bandwidth) or move the mouse to a menu or toolbar. Instead, the user could just say, "Rotate this sixty-two degrees." Speech is also useful when a keyboard or mouse is not available or if a user's hands are busy.

Multiple people in front of machine: Speech recognition is good when several people are using the same application on a single computer.

Limitations to speech

Although speech is a maturing technology, there are a number of scenarios in which speech technology is not appropriate.

Most speech recognition systems break down when they have to recognize more than 100 commands. Selecting from large lists of words or commands imposes fast lookup and comparisons with words or commands that begin to sound similar. Menus and dialog boxes work well with this limitation but long lists, such as thousands of e-mail names, don't.

Speech recognition also has a tough time with spelling because so many letters (for example, M and N) sound alike. Additionally, entering long sequences of letters or numbers can produce a higher error rate. The command "Call five seven nine eight" might end up being "Call nine seven nine eight."

Here are a few other disadvantages:

• Pointing devices: Repeating directions such as "up, up, up, left, left, up, up, up" can get annoying very quickly.

• Games or multimedia: Although speech can enhance a game or interactive multimedia, it is difficult to do quickly on top of filtering out background noise, such as music or game sounds, from the application itself.

• Listening to long passages: Long passages of text-to-speech are hard to listen to. Synthetic voice can be particularly irritating in long passages. Pre-recorded voice always sounds better and more natural than mechanical text-to-speech. So, if storage is not an issue, recorded voice can be more appealing in many scenarios. Still, try not to read long passages of text, especially of a recurring message, and without a cancel of some sort.

What it takes to make speech work

Three converging technologies make speech on Windows possible. Speech used to require specialized hardware capable of signal processing in real time. But with ever-faster CPUs, this is no longer the case.

The second is the emergence of PCs with audio. Most new PCs come with audio hardware built in. Speech can now use this high-volume hardware rather than costly specialized and custom hardware.

The third is easy accessibility to speech technology. The Microsoft Speech API is designed to do that, giving developers a standard programming interface that provides consistent access to speech technology. By using the API, you enable your application for speech technology.

In addition to the Speech API, you'll need either Windows 95 or Windows NT 3.5 (or 3.51) and a speech engine. Speech engines are available through third-party vendors, and often come bundled with sound cards or audio-enabled PCs. Microsoft has its own speech recognition engine that it's working on.

The Speech API provides an interface between your applications and speech engines. (The industry often refers to the application vendors as speech client writers.) Microsoft is working with engine writers to enable their engines to work with the Speech API standard. This will allow client writers to make their applications speech-enabled and give their users total freedom to choose the speech engine writer they need. For example, a user may choose one engine because it has much higher accuracy, trading off speaker independence because it doesn't need it.

The role of the Component Object Model

Windows speech technology is part of the Windows Open Systems Architecture (WOSA). All of the Speech APIs are accessed through the OLE Component Object Model, and they derive significant benefits from an object-oriented approach.

The API also provides access on two levels. The higher level is relatively easy to use and provides quick implementation for simple commands. For developers who need more flexibility for operations such as dictation, the lower level essentially permits an application to talk directly to the speech engine. This is more difficult, but more powerful and flexible.

For more information:

• Look for more articles on speech in future releases of the Microsoft Development Library.

• Send e-mail to MSSpeech@microsoft.com.

• Visit the Speech API section on the WinEXT forum on CompuServe.

• To apply for the beta, download the application form from the library on WinEXT and send it to MSSpeech@microsoft.com. The next beta release should be in the third quarter of 1995.

• Look for the Speech SDK, scheduled to be available in the fourth quarter of 1995.

• Contact speech engine vendors directly.

Jerry Drain is a member of Microsoft's Developer Relations Group, where he works with ISVs on Windows NT and Windows 95.

Mike Rozak is a member of the Personal Systems Division, where he is working on the Microsoft Speech API.

Hardware Speak

Here is the type of hardware needed for speech:

• CPU speed: The typical speech engine requires a 486DX/33 or faster, although the requirement can range anywhere from a 386/16 to a 486/66 for discrete dictation, or to a RISC for continuous dictation.

• RAM: Again, the amount needed depends on the objective. For simple command and control execution, an application will need about 1 megabyte (MB) of RAM above its normal requirement. Something as complex as dictation, however, can require an additional 8 MB of RAM.

• Audio input and output: A sound card and either speakers or headphones are needed. Almost any sound card will do, including Sound Blaster, Media Vision, ESS, and Windows Sound System-compatible cards, and audio built into multimedia PCs. A few speech recognition engines still require specialized DSP cards.

• Microphone: Two types come to mind. Headsets with close-to-mouth microphones have their advantages, allowing users to speak more quietly and reducing interference from background noise. The cord, however, is a disadvantage (hey, somebody come out with an infrared version, okay?). The alternative is medium-distance microphones that often sit near the monitor or CPU.


New UI Features for Development Library

Streamlined data preparation process means richer content

Mike Colee

July 13, 1995

With the July release of the Microsoft Development Library, the hard-chargin' Developer Network development team unveils a new version of our Development Library browsing technology.

InfoViewer version 2.5—produced in collaboration with Microsoft's Visual C++ and the operating systems groups—removes many of the obstacles that have hampered our efforts to deliver richer information in a more timely way.

New UI features

We've freshened up the user interface in InfoViewer 2.5, based on feedback from subscribers as well as from the folks within Microsoft who assisted in the design of InfoViewer. The new UI features include:

• An updated contents pane tree control UI that conforms more closely to the Windows 95 standard.

• A topic toolbar that has been moved to the top of the topic pane to conform more closely to the standards established for Visual C++ embedded toolbars.

• An ability to hide the embedded topic pane toolbar and the topic nonscrolling region.

• Support for pop-ups. Pop-up topics containing term definitions should show up in the July Development Library in the new Win32 docs. Look for more widespread use of pop-up topics in future releases.

Pop-up topics will start popping up in the July Development Library.

• Easier-to-use bookmarks. Setting bookmarks now requires only two mouse clicks.

• New toolbar buttons for defining subsets, choosing subsets, and navigating bookmark and search result lists.

• Support for "See Also" topics. A drop-down menu button on the embedded topic window toolbar will provide a list of topics related to the currently viewed topic. See Also topics will provide extremely valuable cross-reference and related topic links in much of our reference documentation. We don't expect to acquire documents that use this feature for the July release, but in future releases we expect to receive documentation that makes extensive use of it.

• Support for SHED graphics means those cool class-hierarchy bitmaps in the Microsoft Foundation Class Library (MFC) documentation will now be "hot," containing links to the appropriate class overview description. (Again, we may not receive documents that use this feature in time for the July Library release.)

• Expanded automatic hot-linking capabilities. Users can now highlight a word and press F1, which will cause the keyword index to come up with the selected word entered. This allows a quick lookup of keywords that could not be automatically hot linked because they are too generic (for example, OPEN).

WYSIWYG copying and more

Because InfoViewer 2.5 is built on a new release of the MediaView libraries, we have implemented copy as RTF. On a copy operation, you'll now get formatted text and graphics in the form of an RTF stream suitable for pasting into Word for Windows. At the same time, unformatted text is placed onto the Clipboard for use by programming editors or applications that handle only unformatted text.

Other less-visible improvements in InfoViewer are double-byte character set (DBCS) enabling and something we call topic-centricity. Topic-centricity is designed to give documentation authors more control over the structure of the table of contents—for example, the ability to place a topic in more than one place.

InfoViewer 2.5 offers Library users new options for showing and hiding toolbars, topic titles, and title tips, and for configuring pop-up and hot-link colors.

Why these changes? A little background

The release of InfoViewer 2.5 comes a year after the delivery of version 2.0 of the Development Library browser. Our goal then was to update the Library's core viewing/browsing technology by building on a new Microsoft layout and search technology called MediaView. We also improved the UI by implementing many of the features and improvements our subscribers had requested.

But still problems persisted. For example, after looking long and hard at our process for bringing content from the authors to the CD, we found that documents often required an inordinate amount of preparation. Sometimes information had to be ignored or removed from the documents, because either our production process or our browser couldn't utilize it.

For example, the Help file versions of some documentation contain a richer set of hot links and cross-reference information than their equivalents in the Library. (An example of this is See Also information.)

Much of the information we deliver in the Library is also distributed in different forms by various Microsoft groups. For example, the Visual C++ group distributes documentation for the MFC library, C run-time library, and C/C++ language in both printed and electronic form with its products. Ditto for the systems programming documentation.

Less pain, more gain

It may seem that placing this documentation on the Development Library CD would be easy. Unfortunately this isn't always the case. Because most of the documents we receive have been prepared for distribution through Help files or a printed medium, formatting, hot links, and related topic information must be translated into a form that is useful for the Development Library browser. Parts of this process can be very labor intensive.

As a result of the joint effort by the Developer Network, the Visual C++, and the operating systems teams, we will now receive documentation from two of Microsoft's largest documentation-producing groups that has already been prepared for use with InfoViewer 2.5. This means not only a dramatic reduction in our document preparation work but also the delivery of richer and higher-quality development information in a more timely manner.

Looking to the future

We are not resting on our laurels. As you read this article, we are working on continuing to improve the usability of the Development Library. As always, your suggestions for the Library are needed and welcome.

Mike Colee, a Developer Network design engineer, worked on the new InfoViewer version 2.5. He would no doubt be a world-class cyclist were it not for his devotion to the Development Library UI.


Programming for the Windows 95 Game SDK

Jason Robar

July 13, 1995

The Windows 95 Game Software Developers Kit (SDK) offers game developers new tools and technology to help create high-performance games.

The Game SDK provides a standard set of system services. Under MS-DOS, developers had to implement and maintain such services themselves. The SDK also meets or exceeds the functionality available on the next generations of game consoles, while enabling functionality unique to the PC game platform.

The role of Windows 95

Windows 95 makes installing and configuring games and game peripherals easier with features such as Plug and Play and AutoPlay.

Currently, the Windows 95 game subsystem is available only as part of the Windows 95 Game SDK but will be built into future versions of Windows. The game subsystem is royalty-free, and the run-time library will be redistributed by game developers with their Windows 95-based games.

The Game APIs provide device independence and broad hardware support for a wide range of game peripherals without sacrificing speed or functionality. The architecture is based on the Component Object Model (COM). For an introductory look at COM, see "COM: A Model Problem Solver," MSDN_COMODEL Developer Network News, March/April 1995.

The Game SDK provides the following functionality:

• DirectDraw for high-speed graphics

• DirectSound for sound mixing

• DirectPlay for multiplayer communication

• DirectInput for handling game input devices

DirectDraw

DirectDraw provides a device-independent way for games and Windows library software, such as 3-D graphics packages or digital video codecs, to access display device-dependent features. It allows direct linear manipulation of video display memory, hardware blters, hardware overlays, page flipping, and control of the palette and mode setting on the fly. This enables better graphics for animation.

By using DirectDraw, programmers will have access to features that previously required device dependence, such as:

• Support for multiple-buffered and page-flipped animation.

• Access to and control of the video card blter.

• Hardware-assisted overlays with z ordering.

• Support for 3-D z buffers.

• Direct access to 3-D texture maps with or without palettes.

• Tight integration with 3-D hardware acceleration.

• Improved video playback quality through access to YUV color formats.

• Improved graphics and video quality through access to image-stretching hardware.

• Translucency.

• Transparency.

DirectDraw is composed of three major components:

• The DirectDraw object manages the DirectDraw drivers' global functionality and represents the display device. Display modes, resolution, and color depth are controlled through the DirectDraw object.

• The DirectDraw surface is simply a linear area of memory. It contains the device-dependent bits that represent a directly displayable object.

• The DirectDraw palette is a 16- or 256-color indexed palette provided for textures, offscreen surfaces, and overlay surfaces, which might not have the same palette as the primary surface.

To achieve greater speeds, DirectDraw will use whatever hardware acceleration features are present and will employ software emulation for unsupported features. It also allows an application to determine easily the hardware functionality and software emulation capabilities so it can optimize its graphic demands based on how a system will perform.

The graphic methods that game programmers rely on are provided for in a simplified low-level API that does not sacrifice speed for functionality. By providing developers with a simple method to use the features that most video cards already provide (such as hardware blting), games under Windows 95 can achieve screen updates faster than anything that is practical to implement under MS-DOS.

DirectSound

DirectSound is the audio equivalent of DirectDraw. Developed in conjunction with PC audio expert John Miles, the DirectSound APIs were created to provide high-fidelity, low-latency sound and sound mixing. This enables realistic sound effects for Windows-based games.

DirectSound allows direct access to the hardware sound channel of an audio card. It does this by virtualizing the direct memory access (DMA) buffer, enabling direct access to on-card audio buffers, or emulating this for sound cards, such as the current generation of PCMCIA cards.

By using DirectSound, a game can store different sounds into different memory buffers. These buffers can be easily mixed and played quickly without the latency problems associated with Windows 3.x. DirectSound provides this functionality while maintaining compatibility with existing Windows 95-based applications and device drivers.

DirectSound is composed of two structures—the DirectSound object, which represents the sound card, and DirectSoundBuffer objects, which represent the sounds.

DirectSound is essentially an audio buffer manager. An application can employ DirectSound to create DirectSoundBuffer objects. These objects represent audio streams that can be written into directly. The application can mix audio data into these buffers, position these buffers in 3-D space, and play them. A DirectSoundBuffer object may be any of the popular formats currently supported by the WaveOut APIs. This includes mono or stereo; 8 or 16 bits; and 8, 11, 22, or 44 kHz.

The DirectSound object controls the sound card, which includes all of the operating parameters for the sound card and listener for 3-D audio. It is designed to give demanding applications control of the sound card when required. This enables very responsive, high-fidelity sound.

DirectPlay

To simplify adding multiplayer functionality to games, the DirectPlay component provides a method for two or more players' games to communicate.

DirectPlay provides a common interface for a game to use in order to establish a link to other games and handles providing the communication with the other machines. The application itself no longer has to provide the code for communicating data to other machines.

DirectPlay is made up of two pieces—the DirectPlay object that a game communicates with and the DirectPlay servers that the DirectPlay object uses. Microsoft will supply DirectPlay servers for modem, serial, and network connections. Any third party can also provide DirectPlay servers for specialized hardware or online communication services.

When a player wants to begin playing with other players, a list of the available servers can be presented to the player. After the player makes the selection, the game uses DirectPlay to establish the connection and handle the communication.

To adjust for communication performance, the game can query the DirectPlay object for the current latency and bandwidth of the communication method. The game can also query the DirectPlay object for information about previous and existing game play sessions.

A game using DirectPlay does not have to worry about whether it is using a modem or a network or an online service provider, thus saving developers time.

DirectInput

For a game to find out what a player wants to do, it needs a method to communicate with an input device. For the PC, the analog joystick has remained the standard by default for over a decade. This hasn't improved because the analog joystick method does not permit innovations in input device design. DirectInput is an API that solves these problems and provides even greater functionality.

By abstracting a game away from programming directly to the hardware, DirectInput allows Windows 95 to support a more diverse range of devices as they become available, such as headtrackers or digital joysticks. This also allows manufacturers to develop new designs without having to worry about compatibility with existing games. If a game was developed using DirectInput, a new minidriver is all that's needed for the game to make use of a new device.

DirectInput supports up to 16 input devices simultaneously, each with up to six axes of motion and n number of buttons. It also allows for increased performance through serial and digital input, while still supporting the current analog method.

This architecture also supports devices that react to data from the application (known as "force feedback"). A simple example of this is a steering wheel device that shakes when the player drives over rough ground.

With these features, DirectInput frees developers from worrying about which input devices to support, and allows hardware manufacturers to develop new designs without achieving industry acceptance beforehand.

How to get the Game SDK

The Game SDK is currently in beta but is scheduled to be available this fall. To receive a beta copy, e-mail betareq@microsoft.com with your contact information (name, address, e-mail, phone, fax, and so on) and specifically request the Windows 95 Game SDK Beta. Support sections are currently available on CompuServe in the WINMM forum.

The Windows 95 Game SDK represents an evolutionary leap forward for the Microsoft Windows API. By using the game subsystem, Windows 95-based games will be the best available on any platform.

When he's not evangelizing the gaming world about the Ultimate Gaming Platform (UGP), Jason Robar enjoys exploring the clubs and cafes of Seattle, looking for the perfect band or the perfect spot to relax and read in Russian.


The Shape of Platforms to Come

Developer Network trims number of CDs in U.S., Canada

John Rae-Grant

July 13, 1995

Here's how rumors start: First, we at the Developer Network decide "Hey, let's ask subscribers what they think about the Developer Network."

Then we have to decide what to ask and how to ask it. (Don't laugh, this isn't as easy as it sounds.) Once we've made that hurdle, we prepare to solicit your feedback. We hold focus groups. We send out surveys. We knock on doors. We keep our eyes open for two-yolk eggs and strangely shaped clouds.

Then, like wildfire, the whispers—soon to transmogrify into a thunderous roar—start. "Pssst, the Developer Network is going to be, gulp, changing."

Uncertainty and suspicion ensue. I guess that's natural. After all, change can be, well, unsettling. The current situation may have its little problems and hiccups, but at least you kind of know what to expect. We here at the Developer Network are in the same boat when it comes to change. We know that while our current offerings don't satisfy all your needs and sometimes engender complaints, they do work for a large number of subscribers.

But we are also faced with the reality that we have to change. How else can we keep you up-to-date? It was a huge change when we made the Development Platform available through our Level 2 membership. It was a major step when we started publishing Developer Network News and technical information on the World Wide Web (and now The Microsoft Network). It was change when we started dedicating more attention to Visual Basic and OLE.

Does that mean everybody is happy with our changes? Probably not. Does that mean we don't make mistakes? Probably not. Does that mean we should stop trying to improve our program? Definitely not. If we didn't change, we'd still be selling copies of Microsoft QuickBasic and Typing Tutor door-to-door.

Still, you have a perfect right to be thinking, "Now they're gonna remove everything I care about from the Development Platform and leave only that stupid checkbook sample! Then they're gonna make me pay through the nose each week for each individual bit."

Well, I'm here to tell you, "Not so." (Oh, I forgot to introduce myself. I'm John Rae-Grant. How are ya?)

We are going to tune Level 2. The reason is pretty simple. It's TOO BIG! Many of you told us not only do you not want many of the platform contents, but also that you think we are holding back on good stuff because it's TOO BIG!

One Level 2 member thoughtfully shared his pain with us in this way: "I'm just not getting the use I thought I would out of the Finnish version of Windows NT 3.5 ever since that CAD/CAM numerical process control project for Santa's Workshop fell through."

Our Development Platform is in danger of gravitational collapse due to sheer volume. So, we plan to remove some less popular stuff from CDs that Level 2 members in the United States and Canada automatically receive each quarter. (In other countries, local subsidiaries will decide whether and how to implement any changes.)

By separating out the international versions of the operating systems (12 CDs) and the device driver kits (3 CDs), we can trim the number of Platform CDs from the current 19 to about 4.

This change won't be fully implemented until the October release because we couldn't get our act together to save all these discs in July. You'll notice, however, that the July Platform contains three separate packs:

• U.S. pack—U.S. versions of Windows and Windows NT Workstation operating systems (retail and debug, when available), resource kits, software development kits (SDKs), and the Setup program.

• International pack—International versions of Windows and Windows NT Workstation operating systems, SDKs, and SDK extensions.

• DDK pack—U.S. and international versions of device driver kits (DDKs) and DDK extensions.

Does this mean you can no longer get the Finnish version of Windows NT 3.5 if you want? No. We are making everything we removed available through optional add-on programs. This means you'll have to let us know if you want to keep receiving anything that we've removed from the basic Level 2 package. Within a month or so after you receive the July release, we'll be sending out a card explaining how to "qualify" yourself for the International and/or DDK pack.

As the new "muckamuck" around here, my goal is a program as responsive and successful as possible, so please keep that feedback coming. We really are listening.

John "Johnny the Fish" Rae-Grant is the new business unit manager of the Microsoft Developer Network.


Subscribers to See Visual C++ 2.2 in July

Jonathan Kagle

July 13, 1995

In late July, Microsoft Visual C++ subscribers are scheduled to receive a new subscription release. Visual C++ version 2.2 provides extra support for developers who want to take advantage of the new features of Windows NT 3.51 and the upcoming Windows 95 release.

The new release includes updated functionality in the 32-bit version of the Microsoft Foundation Class Library (MFC), the Windows NT 3.51 Step-Up Kit, new Win32 Software Development Kit headers and libraries shipped for the Windows NT 3.51 release, and numerous bug fixes.

New features for Windows 95 and Windows NT 3.51 development

Visual C++ 2.2 contains up-to-date header files, import libraries, and Win32 API documentation for writing Windows NT- and Windows 95-compatible applications. (There are no longer separate headers for Windows NT and Windows 95.)

Visual C++ 2.2 also includes MFC version 3.2, with classes for OLE and database programming. The following new features have been added to MFC in the 32-bit product:

• Updated MFC classes to work with the new common controls recently released in Windows NT 3.51 (and soon available in Windows 95 and a future version of Win32s).

• Support for the new Windows common controls in USRDLL projects.

• Improved and updated common control documentation.

• New MFC sample applications covering topics such as OLE, AVI, and screen savers. There's also source code for the Windows 95 WordPad applet.

In addition, MFC and C run-time library dynamic-link libraries (DLLs) have been tuned to reduce swapping in low-memory conditions.

Windows NT Workstation 3.51 Step-Up Kit

This release also includes an upgrade from Windows NT 3.5 to 3.51 for Intel x86 or compatible machines. Windows NT 3.51 includes support for the new common controls, making development for Windows 95 easier. (Developer Network Level 2 subscribers already have this version.) The upgrade kit requires Windows NT Workstation version 3.5.

Other new features

Many other items are included in this subscription release:

• The OLE Control Developer's Kit, which includes the ability to use the new MFC common control classes in your OLE Controls

• Visual C++ 1.52b, which fixes several bugs

• Win32s 1.25a, which includes many bug fixes, removes the 128K stack limitation, and enhances internationalization support as well as compatibility for Novell NetWare and Stacker

• Selected presentations, white papers, and source code from the first annual MFC conference

Availability

The Visual C++ subscription provides multiple-platform support for Microsoft Windows 95, Microsoft Windows NT running on Intel platforms, and Windows 3.1 with Win32s. Subscriptions are now available in the United States, Canada, and Western Europe. Elsewhere, the CD will be available as a stand-alone upgrade through local Microsoft subsidiaries.

Versions of Visual C++ 2.0 remain available for Apple Macintosh 68K platforms, Digital Equipment Corporation's Alpha platform, and the MIPS platform.

Jonathan Kagle is a product manager for Visual C++ and Microsoft Test. He vehemently denies that he is being bundled with Windows 95.

Where's My Visual C++ 2.2 CD?

Well, there are several possibilities:

• It's still July. It takes a while to ship out all those CDs!

• You haven't activated your subscription. Many people who bought the Visual C++ subscription have still not sent in their activation cards (which are cleverly hidden next to the MFC hierarchy chart). If you lost it, call (800) 719-5577 and have your product ID number ready.

• You live outside the United States, Canada, or Western Europe. We're working hard to make the subscription available everywhere, but in other countries this CD is available as a stand-alone upgrade through your local subsidiary.

• You bought the nonsubscription edition. If you live in the U.S. or Canada, you can upgrade to the Visual C++ subscription by sending in the upgrade card in the box. If you've lost the card, call (800) 719-5577 to place your order. In Western Europe, contact your local Microsoft subsidiary.

• Something else went wrong. Call (800) 719-5577 or contact your local subsidiary with your product ID number to get problems worked out.


Using OLE Automation in Visual FoxPro

Paul Bienick

July 13, 1995

Since the introduction of the Microsoft FoxPro database management system for Windows, developers have been able to use OLE technology to embed or link documents from other applications directly into FoxPro tables. Now Visual FoxPro 3.0 goes much further, allowing you to use OLE Automation to add the functionality in Microsoft Office products—such as Microsoft Word and Microsoft Excel—to applications created with FoxPro.

An OLE Automation server application allows other, external applications to control it by exposing certain parts of its internal structure in the form of objects. These objects have properties and methods. Properties allow you to set or retrieve values that might represent the state of the object. Methods allow you to perform an action on a specific object, such as opening a new document, printing a file, or recalculating a range of cells.

Quick review

You need to consider only two FoxPro functions to retrieve another application's objects: CreateObject and GetObject. Once you have obtained the object, you can immediately begin to access its properties and methods.

CreateObject creates an object from a class definition or an OLE object. It is also used to create objects of built-in FoxPro or user-defined classes:

<memvar> = CREATEOBJECT(cClassName)

cClassName specifies the OLE object from which the new object is created. FoxPro will search for the class name you specify in the following order:

1. Visual FoxPro base classes.

2. User-defined class definitions in memory in the order they were loaded.

3. Classes in the current program.

4. Classes in .VCX class libraries opened with SET CLASSLIB.

5. Classes in procedure files opened with SET PROCEDURE.

6. Classes in the Visual FoxPro program execution chain.

7. The Windows registry (for OLE objects).

OLE objects are created using the following syntax for cClassName:

ApplicationName.Class

For example, to create a Microsoft Excel object using OLE Automation, use the following:

xl = CREATEOBJECT("Excel.Application")

When this code is run, Microsoft Excel is started but is not visible. If Microsoft Excel is already running, another separate instance is created when you execute this command.

GetObject activates an OLE Automation object and creates a reference to the object. For example:

GETOBJECT([cFileName [, cClassName]])

cFileName specifies the full path and filename to activate. The application does not need to be specified, because the OLE dynamic-link libraries (DLLs) determine which application to start based on the filename provided.

For example, the following code launches Microsoft Excel, opens a file named BUDGET.XLS, and creates a reference through an object memory variable named xlBudget:

xlBudget = GETOBJECT("C:\EXCEL\WORK\BUDGET.XLS")

cClassName specifies the class name of the object to retrieve. Some applications can store more than one object type in the same file, allowing you to use the class name to specify the object to activate. For example, if a word-processing application stores its documents, macro definitions, and toolbar objects in the same file, you can create a reference to the document file with the following command:

mDocFile = GETOBJECT("C:\WRDPROC\MYDOC.DOC", "WrdProc.Document")

With some server applications, each time a GetObject function is called an additional instance of the application is started, which uses additional memory. For example, if Microsoft Excel is already running, you can prevent additional instances from starting by omitting cFileName and including cClassName, as in this example:

xl = GETOBJECT(, "Excel.Application")

If Microsoft Excel is not running, a trappable error will be generated. Trapping the error and resorting to the CreateObject function is a common technique to test if an application is already running. An alternative technique is to use dynamic data exchange (DDE) to establish a link with the server application on the System topic, which all DDE applications support. If the link is successfully established, the application is running.

The registration database

The registration database is where FoxPro looks for the class name you specify with the CreateObject and GetObject functions. Under the Windows 3.11 and Windows for Workgroups 3.11 operating systems, entries into the registration database are stored as keys, with a corresponding value for each key in a tree-like structure. You can view the registration database with a program called REGEDIT.EXE, which is located in the directory where you installed Windows. Run REGEDIT with the /V option to see more detail.

Under the Windows NT and Windows 95 operating systems, look under the HKEY_CLASSES_ROOT category or window to find entries for OLE Automation objects. The Windows NT 3.5 registration database editor was invoked by running the REGEDT32.EXE program with no options, as illustrated in the following figure.

Windows NT registration database

Object-oriented extensions in Visual FoxPro 3.0

One of the greatest advantages of using OLE Automation from within Visual FoxPro is the new object-oriented extensions. Because you now can create custom classes, and because classes serve to encapsulate both data and behavior, you can build classes that shield you from the peculiarities of a specific type of OLE server application.

To illustrate this, let's look at the differences between controlling Word and Microsoft Excel. Begin by developing an abstract class that defines how to control all OLE applications. A subclass of this class can then be created for each specific OLE application that you want to control.

#INCLUDE "FOXPRO.H"

DEFINE CLASS OLEApplication AS Custom

PROTECTED oOLEApp, ;

cOLERegName, ;

lCloseAppWhenDone

oOLEApp = ""

cOLERegName = ""

lCloseAppWhenDone = .T.

*— Methods

FUNCTION Init()

IF EMPTY(this.cOLERegName)

=MESSAGEBOX("Cannot create object

directly from class

OLEApplication", ;

MB_ICONSTOP, ;

"")

RETURN .F.

ENDIF

IF this.AppRunning()

this.oOLEApp = this.GetCurrentInstance()

ELSE

this.oOLEApp = this.CreateNewInstance()

ENDIF

ENDFUNC

*— Additional methods get inserted here

ENDDEFINE

This defines the core functionality of your abstract OLEApplication class. First check to ensure that a user of the class is not trying to instantiate it directly. If so, just cancel the INIT method, which prevents the object from being created. Then check to see if the application is running. If it is, create a reference to it. If not, create a new instance.

You need to determine if the application you're trying to control is currently running because certain applications, such as Microsoft Excel, let you create multiple instances, while others, such as Word, don't. Here are two suggestions to determine if an application is already running.

The first involves using the GetObject function to attempt to retrieve a reference to an OLE Automation server. At the time of this writing, this option works fine with Microsoft Excel, but not with Word. Override this function when you define a Word for Windows class, but for now, define this option as a protected function within your OLEApplication class. (You define the function as protected because you will only be calling this function from within the OLEApplication class or any class that you derive from it. There is no need to expose it to the "outside world.")

PROTECTED FUNCTION AppRunning()

*— Returns .T. if app is already running

LOCAL lcOldError, ;

llRunning

llRunning = .T.

lcOldError = ON("ERROR")

ON ERROR llRunning = .F.

*— Attempt to get a reference to a running application

=GETOBJECT(, this.cOLERegName)

ON ERROR &lcOldError

this.lCloseAppWhenDone = !llRunning

RETURN llRunning

ENDFUNC

To complete the definition of the OLEApplication class, create two methods, also defined as protected functions, that you will use to create references to new instances or retrieve references to current instances. Notice that each method contains only one statement. You could eliminate the overhead of the function call and place the CreateObject and GetObject calls directly in the INIT method, but then you wouldn't be able to customize the behavior of these methods in your subclasses.

PROTECTED FUNCTION CreateNewInstance()

RETURN CREATEOBJECT(this.cOLERegName)

ENDFUNC

PROTECTED FUNCTION GetCurrentInstance()

RETURN GETOBJECT(, this.cOLERegName)

ENDFUNC

The Microsoft Excel class

Define your first subclass to handle OLE Automation with Microsoft Excel. Most of the inherited functionality from the OLEApplication class works just fine with Microsoft Excel. The first thing you need to do is initialize the cOLERegName property with the appropriate name of the Microsoft Excel application object as it appears in the registration database. Then set up a Destroy event method that sends the Quit command to Microsoft Excel whenever the object is being destroyed. The Destroy event method will fire whenever you explicitly release a Microsoft Excel object, or whenever the Microsoft Excel object goes out of scope.

DEFINE CLASS Excel AS OLEApplication

*— Inherited properties

cOLERegName = "Excel.Application"

*— Methods

FUNCTION Destroy()

IF TYPE("this.oOLEApp") == "O" AND ;

this.lCloseAppWhenDone

this.oOLEApp.Quit()

ENDIF

ENDFUNC

ENDDEFINE

The Word for Windows class

The second way to determine if an application is already running involves the use of DDE. This is useful in Word because the GetObject function doesn't work properly with Word. To check if an instance is running, it's necessary to use DDE to attempt to establish a link with Word. If you are successful, you know that Word is running, so you immediately terminate the link.

In doing so, you also define a new implementation for the GetCurrentInstance method. This is because of Word's inability to respond to the GetObject function. To get the current instance of Word, you can safely use the GetObject function, passing an empty string as the first parameter.

DEFINE CLASS WinWord AS OLEApplication

*— Inherited properties

cOLERegName = "Word.Basic"

PROTECTED FUNCTION AppRunning()

LOCAL lnChannel, ;

llRunning, ;

llDDEOldSafety

llDDEOldSafety = DDESETOPTION("Safety")

=DDESETOPTION("Safety", .F.)

lnChannel = DDEINITIATE("WinWord", "System")

IF lnChannel <> -1

*— It's running

this.lCloseAppWhenDone = .F.

=DDETERMINATE(lnChannel)

llRunning = .T.

ENDIF

=DDESETOPTION("Safety", llDDEOldSafety)

RETURN llRunning

PROTECTED FUNCTION GetCurrentInstance()

RETURN GETOBJECT("", this.cOLERegName)

ENDFUNC

ENDDEFINE

It is interesting to note that Word does not support creating multiple instances of itself through OLE Automation, while Microsoft Excel does. Using the classes presented here will prevent you from having to worry about inadvertently creating another instance of Microsoft Excel.

Another interesting difference between these two applications is that when releasing a reference to Word that was started through OLE Automation, the Word instance is automatically terminated. However, a reference to Microsoft Excel will not terminate in this fashion. Instead, we must send the Quit method to the Microsoft Excel object, explicitly instructing it to terminate. Furthermore, Microsoft Excel will terminate even if the reference to it was created from a previously running instance.

Providing access to the reference

Note that the reference to the OLE Automation server is a protected member of the OLEApplication class. This means that you can only access this reference through methods of the class or one of its subclasses. There are three approaches you can take to provide access to the reference:

• Unprotect the oOLEApp property. This will provide direct access to the reference from outside the class's methods. This is the most dangerous option, as you then lose control of the reference.

• Create a method that simply returns the reference. This is somewhat less dangerous than the first option, but care must be taken since you now have two references to the same object.

• Create custom methods to manipulate the protected reference. This option is preferred, as you maintain almost complete control over the reference, even though more work must be done initially.

For more details

This article is based on a presentation made by the author at Tech•Ed 95. For a more detailed discussion of this material, please see "Using OLE in Microsoft Visual FoxPro" by Paul Bienick in the July 1995 release of the Microsoft Development Library.

Paul Bienick is a software engineer at Flash Creative Management, a New Jersey firm specializing in helping companies improve business processes. He can be reached on CompuServe at 71510,3217.

Dealing with Complex Object Models

Microsoft Excel provides more than 100 objects, each of which has a myriad of properties and methods. You don't have to memorize each property and method to be productive with Microsoft Excel but it does help to become familiar with what's there.

A great way to learn how to use these properties and methods is through Visual Basic for Applications, which includes the Microsoft Excel built-in macro language. Visual Basic for Applications uses the same objects, properties, and methods available to FoxPro through OLE Automation. In fact, Visual Basic for Applications itself uses OLE Automation to communicate with Microsoft Excel.

Knowing this, you can use the macro recorder built into Microsoft Excel to record the functionality you are trying to model. The macro recorder generates Visual Basic code, which you can examine to see how various objects are being used. Granted, not every construct in the Visual Basic programming system is directly portable to FoxPro, but Visual Basic interacts with Microsoft Excel in much the same way as FoxPro, and the syntax when dealing with Microsoft Excel objects is almost identical. In many cases you may discover new objects or techniques.

Another great way to become familiar with an application's objects is through the command window, from which you can interactively create objects, set object properties, and call object methods.


Yes, Virginia, Windows 95 Does Do Unicode!

Creating Unicode apps for Windows 95

Nadine Kano

July 13, 1995

Windows NT, an operating system built from the ground up, processes characters internally in Unicode.

Windows 95, an operating system that originates from the code base for Windows 3.x, processes characters internally in local character sets—the same character sets used by Windows 3.x.

Therefore, we can safely say that Windows NT does Unicode, but Windows 95 does not, right? Not exactly.

What does "doing" Unicode mean?

First of all, what does it mean to say that an operating system "does" or "doesn't do" Unicode? Windows 95 itself does not process strings in Unicode. The Win32 API on Windows 95 expects all string parameters to be encoded in the local character set of the system; the default local character set changes depending on the language edition of Windows 95 (except for the five wide character APIs listed below).

For example, Western European editions use the ANSI character set (also called code page 1252), while the Eastern European editions use code page 1250, and the Japanese edition uses Shift-JIS (also called code page 932). So you can say that Windows 95, the operating system, does its internal processing in local character sets only.

This limitation does not, however, extend to applications that run on the operating system. Even though Windows 95 doesn't process strings internally using Unicode, applications running on Windows 95 still can!

If you are dealing with multilingual documents, you may prefer to store all your data in Unicode, because it provides unambiguous code point values for a wide range of characters used in a wide range of languages. If your application processes Japanese, Chinese, or Korean characters, you may find it easier to manipulate strings in Unicode, which is a fixed-width character set, unlike alternative character sets, which are a mixture of one- and two-byte encodings. Unicode is also a good means for sharing data with other systems.

Translating needed

If you want to base your application on Unicode and run it on Windows 95, you need to translate string parameters to local character sets before calling API functions. (The only wide character APIs that handle Unicode on Windows 95 are TextOutW, ExtTextOutW, GetCharWidthW, GetTextExtentW, and GetTextExtentPointW.)

The API for translating strings from Unicode into the system's default local character set is WideCharToMultiByte. When you receive string-based information from Windows 95, you need to translate it into Unicode by calling MultiByteToWideChar before working with it.

Obviously translating strings to and from Unicode every time you call an API that takes string parameters adds overhead to your program. It's up to you to weigh the pros and cons of this approach to suit your program's requirements.

Local character sets on Windows NT

Perhaps it makes more sense for your application to use local character sets. Unicode's 16 bits per character may be too large to accommodate your space constraints, even with compression. You may have an existing code base that uses local character sets and meets your needs. If your application is based on a local character set, will it still run correctly on Windows NT? Absolutely.

Windows NT supports two flavors of the Win32 API—'W' or wide character entry points, for string parameters encoded in Unicode, and 'A' or ANSI entry points, for string parameters encoded in local character sets. If you call the A entry points, Windows NT will automatically convert the string parameters into Unicode before calling the W version of the same function. For this reason, using local character sets while running on Windows NT does add some overhead to your application.

Creating a single binary

What if you want to create a single binary that will run unchanged on both Windows 95 and Windows NT? Is this possible? If so, which character encoding should you use?

Because both Windows 95 and Windows NT can handle either Unicode or local character sets, you can create a single binary to run on both systems and you can choose the character encoding that makes the most sense for your application. The GetVersionEx API function will tell you at run time which operating system your application is running on. Based on this information, you can take the appropriate steps.

For example, let's assume that your application is based on Unicode. If you determine that it is running on Windows NT, you can call the wide character API entry points directly. When the same application runs on Windows 95, you will have to convert string parameters to the system's local character set with WideCharToMultiByte before calling the ANSI-based API entry points.

Even though W APIs are not implemented on Windows 95, their entry points are stubbed. Therefore, it is safe to write code that calls the W APIs. If your application is based on a local character set, simply call the A versions of the Win32 API functions—both Windows NT and Windows 95 support them. (Don't forget that there are slight differences in the API sets for Windows NT and Windows 95.)

It's important to remember that Unicode support on Win32 is not a black-and-white, all-or-nothing issue. You can create Unicode-based applications for Windows 95 even though the system itself isn't based on Unicode. At the same time, just because Windows NT is fully Unicode-based internally doesn't mean that your application is required to use Unicode when it runs on Windows NT.

Keep in mind that supporting Unicode will not automatically make your application "fully international." Unicode is a character encoding—it can make software internationalization easier in many cases, but it does not help you with culturally accurate sorting; date, time, or currency formats; input methods; user interface translation; text layout; font design and selection; or many other elements that make up an international program.

There are reasons to choose Unicode as your encoding and reasons not to. Win32 gives you the Unicode option, on both Windows NT and Windows 95. You need to decide, based on your users' needs and your development goals and constraints, what will work best for your application.

For more information, see chapter 3 in Developing International Software for Windows 95 and Windows NT, published by Microsoft Press. (That's by me!)

Globalization specialist Nadine Kano just completed a 768-page book on software internationalization. Now she spends most of her spare time sleeping and dulling her brain with sleazy tabloid TV shows.


Ask Dr. GUI #22

(He often wonders what his life would be like if he finished pre-med.)

January 1995

Questions in this issue: Dr. GUI's busy operating schedule won't allow him to answer all questions, but the Good Doctor will answer as many as he can in the next release of the Microsoft Development Library. Send your questions to:

Dr. GUI
Microsoft Developer Network
One Microsoft Way
Redmond, WA 98052-6399

Fax: (206) 936-7329, Attn: Developer Network
Internet: msdn@microsoft.com

Questions in this issue:

Chroma, Chroma, Chroma Chameleon: Altering DIB's

Montana Boy Needs Help: Enabling Menu Items On-The-Fly

Help File to Product Documentation

Obscure OLE Control Question


 Chroma, Chroma, Chroma Chameleon: Altering DIB's

Dear Dr. GUI:

What is the method of choice for changing the contrast and/or brightness of a DIB? I hope you're not gonna tell me I have to iterate through each pixel and add/subtract from the colour value "manually"! I could probably do that, but I don't know how to do gamma correction and all that stuff. So I'm hoping you'll say something like "Oh...use the BrightBlt function."

Steve Yolleck
Toronto, Ontario, Canada

Dr. GUI replies:

I am a master of music trivia. This song was sung by a young man who looked remarkably like an older woman wearing heavy makeup. The makeup was very bad looking but extremely colorful. Which brings me to my point (I think).

There are two approaches to your problem. Assuming that you are targeting an 8-bit-per-pixel (bpp) 256-color display (there is a strong argument that this should be your target display), you can either animate the palette or alter the existing palette entries.

I once wrote a fax application that used palletized color on a 256-color display. The images were all black and white, so I constructed 128 gray scales in the palette. To alter the contrast and brightness I animated the palette, changing the slope for contrast or changing the overall level for brightness.

In my opinion, the best approach is to alter the colors of the bitmap and then redraw it. Palette animation is too dependent on the presence of a palette. In the case of 8-bpp bitmaps, change the palette entries to reflect the desired brightness/contrast and then redraw the DIB (device-independent bitmap). On any other display you need to alter the image by walking through the DIB and altering each pixel (yeech!).


 Montana Boy Needs Help: Enabling Menu Items On-The-Fly

Dear Dr. GUI:

I'm required to add menu items to a menu on the fly in an MFC-based application. I added the items to the menu using AppendMenu and set them as MF_ENABLED, but when I run the application the new menu items are disabled. What can I do?

Christopher Reed
Billings, Montana

Dr. GUI replies:

Well, Christopher, I am partial to Montanans, having been born there. My mother lived in a sod house in Miles City. My father drove taxi in French Town. Odd, you could walk from one end of French Town to the other in less than three minutes! I was born in Great Falls. I was potty trained by the time I was nine months old. My first word was Grizzly. I panned for gold when I was three. I was a smoke jumper for the forest service and was instrumental in the creation of Glacier Park. Then I started grade school. But that is another story!

The reason these items are being disabled is that in the Microsoft Foundation Class Library (MFC) OnInitMenuPopup function, items that do not have a message handler function are disabled. To fix the problem, simply overwrite OnInitMenuPopup in your CMainFrame class and return when nIndex is equal to the menu to which you added items. The following example demonstrates this.

void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
   if (nIndex == CONTENTMENU)   // contents menu
   {
      return;
   }
   CFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);

}

One caveat: If you are using OnUpdateCmdUI to set the text of a menu item, check a menu item, or enable/disable a menu item, you must add special handling for the menus that you are not allowing MFC to handle. In the following example, the application required a bullet on the currently selected menu item, including the added ones.

void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
   if (nIndex == CONTENTMENU)   // contents menu
   {
      UINT nCurrent;

      // First get a pointer to the menu of interest.
      CMenu *pContentMenu;
      pContentMenu = pPopupMenu->GetSubMenu(CONTENTMENU);

      // Now we have to build a CCmdUI class for the menu items.
      CCmdUI state;

      // Set the m_pMenu member variable to the main menu.
      state.m_pMenu = pPopupMenu;

      // Set the m_pParentMenu to the submenu. Sounds funny but trust me.
      state.m_pParentMenu = pContentMenu;

      // The menu ID of the menu item that you want a bullet on.
      state.m_nID = pView->m_lContent;

      // Must be NULL
      state.m_pSubMenu = NULL;
      state.m_pOther = NULL;

      // Set the m_nIndexMax to the number of menu items in the main menu.
      state.m_nIndexMax = pPopupMenu->GetMenuItemCount();

       // This switch figures out which menu index should be marked.
      switch (state.m_nID)
      {
         // Is it one of the four stock menu items...
         case IDM_PRODUCTS:
            nCurrent = 0;
            break;
         case IDM_CD:
            nCurrent = 1;
            break;
         case IDM_NEW:
            nCurrent = 2;
            break;
         case IDM_UPDATED:
            nCurrent = 3;
            break;
         // ...or an appended menu item.
         default:
            nCurrent = state.m_nID - IDM_DEFINESUBSET - SUBSETMENUOFFSET +
                       NUM_STOCK_MENUITEMS;
            break;
      }
      // Check the current item and uncheck the rest since we only want one
      // current.
       for (UINT i = 0; i < state.m_nIndexMax; i++)
      {
         // Set the CCmdUI member variable m_nIndex so that SetRadio knows which
         // menu item to work on.
         state.m_nIndex = i;
         if (i == nCurrent)
            state.SetRadio(TRUE);
         else
            state.SetRadio(FALSE);
      }
      return;
   }
   CFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}

Don't forget to remove any OnUpdateCmdUI functions that you have created for this menu, because they won't get called.


 Help File to Product Documentation

Dear Dr. GUI:

I have created an RTF file for my online Help. I don't have any problems creating the Help file. Now I want to create a manual, but I don't want to retype everything. I have converted the file from .RTF to .DOC, but all the formats (#K and double underline) are kept. The printout doesn't look good, as you can imagine.

Can anyone tell me the best way to do what I want to do? It is too much work stepping through the document and eliminating the stuff I don't want to be displayed. It is enough replacing all references to the bitmap I have used.

Sonja Al-Kass
Germany

Dr. GUI replies:

Piece o' cake, Sonja! This conversion is simple when you become familiar with WordBasic. The code below should be used as a macro in Word for Windows 6.0 and then executed on the desired document. The macro looks for any text that has the "Footnote Reference" style. Whenever this text is found, it is deleted from the document using the EditClear command. It then looks for any double-underlined and underlined text. These characteristics are removed using the EditReplaceFont command.

Sub MAIN
   StartOfDocument
   EditFindClearFormatting
   EditFindStyle .Style = "Footnote Reference"
   EditFind .Find = "", .Direction = 0, .MatchCase = 0, .WholeWord = 0,
           .PatternMatch = 0, .SoundsLike = 0, .Format = 1, .Wrap = 0
   'Remove all Footnote References.
   'WARNING: This may be a different name in German WinWord.
   While EditFindFound()
    If Len(Selection$()) Then
       EditClear
    EndIf
    EditFind .Find = "", .Direction = 0, .MatchCase = 0, .WholeWord = 0,
             .PatternMatch = 0, .SoundsLike = 0, .Format = 1, .Wrap = 0
   Wend
   'Remove all Double Underline.
   EditFindClearFormatting
   EditReplaceClearFormatting
   EditFindStyle .Style = ""

   EditFindFont .Points = "", .Underline = 3, .Color = - 1,
      .Strikethrough = - 1, .Superscript = - 1, .Subscript = - 1,
      .Hidden = - 1, .SmallCaps = - 1, .AllCaps = - 1, .Spacing = "",
      .Position = "", .Kerning = - 1, .KerningMin = "", .Tab = "0",
      .Font = "(normal text)", .Bold = - 1, .Italic = - 1, .Outline = - 1,
      .Shadow = - 1

   EditReplaceFont .Points = "", .Underline = 0, .Color = - 1,
      .Strikethrough = - 1, .Superscript = - 1, .Subscript = - 1,
      .Hidden = - 1, .SmallCaps = - 1, .AllCaps = - 1, .Spacing = "",
      .Position = "", .Kerning = - 1, .KerningMin = "", .Tab = "0",
      .Font = "(normal text)", .Bold = - 1, .Italic = - 1, .Outline = - 1,
      .Shadow = - 1

   EditReplace .Find = "", .Replace = "", .Direction = 0, .MatchCase = 0,
      .WholeWord = 0, .PatternMatch = 0, .SoundsLike = 0, .ReplaceAll,
      .Format = 1, .Wrap = 2

   'Remove all Single Underline.
   EditFindFont .Points = "", .Underline = 1, .Color = - 1,
      .Strikethrough = - 1, .Superscript = - 1, .Subscript = - 1, .Hidden = - 1,
      .SmallCaps = - 1, .AllCaps = - 1, .Spacing = "", .Position = "",
      .Kerning = - 1, .KerningMin = "", .Tab = "0", .Font = "(normal text)",
      .Bold = - 1, .Italic = - 1, .Outline = - 1, .Shadow = - 1

   EditReplaceFont .Points = "", .Underline = 0, .Color = - 1,
      .Strikethrough = - 1, .Superscript = - 1, .Subscript = - 1, .Hidden = - 1,
      .SmallCaps = - 1, .AllCaps = - 1, .Spacing = "", .Position = "",
      .Kerning = - 1, .KerningMin = "", .Tab = "0", .Font = "(normal text)",
      .Bold = - 1, .Italic = - 1, .Outline = - 1, .Shadow = - 1

   EditReplace .Find = "", .Replace = "", .Direction = 0, .MatchCase = 0,
      .WholeWord = 0, .PatternMatch = 0, .SoundsLike = 0, .ReplaceAll,
      .Format = 1, .Wrap = 2
End Sub

The process could be further extended to replace the "{bm? filename}" reference with the actual pictures. This is done in the following macro.

Sub MAIN
   D$ = InputBox$("Enter the directory where the images are located", "Replace
        {bm...}", "C:\VB3\HC\")
   If Len(D$) Then
      If Right$(D$, 1) <> "\" Then D$ = D$ + "\"
   Endif
   StartOfDocument
   EditFind .Find = "{bm", .Direction = 0, .MatchCase = 0, .WholeWord = 0,
                  .PatternMatch = 0, .SoundsLike = 0, .Format = 1, .Wrap = 0
   While EditFindFound()
      While Right$(Selection$(), 1) <> "}"
         CharRight 1, 1
      Wend
      bmp$ = LTrim$(RTrim$(LCase$(Mid$(Selection$(), 6,
         Len(Selection$()) - 6))))
      If Right$(bmp$, 3) = "shg" Then
         bmp$ = Left$(bmp$, Len(Bmp$) - 3) + "bmp"
      End If
      On Error Resume Next   'In case file not found or invalid (i.e. shg).
      InsertFile$ = D$ + bmp$
      InsertPicture .Name = InsertFile$, .LinkToFile = "0"
      On Error Goto 0
      CharRight 1
      EditFind .Find = "{bm", .Direction = 0, .MatchCase = 0, .WholeWord = 0,
                    .PatternMatch = 0, .SoundsLike = 0, .Format = 1, .Wrap = 0
   Wend
End Sub


 Obscure OLE Control Question

Dear Dr. GUI:

I am working with a client who is trying to make a call to a DLL from within an OCX. Since the OCX is using OCX30.DLL and the DLL is using MFC30.DLL, this seems to be a problem. The problem occurs with memory allocation between the two parts. Something allocated by the OCX cannot be freed by the DLL, and vice versa. Is this supposed to work?

As a workaround, we've made the DLL use OCX30.DLL instead of MFC30.DLL by changing the linker settings. This seems to work fine, but we always get a memory leak at termination (DYNALINK.LIB at 490A94). What's going on here? Which approach should we use, and how do we use it properly?

Dr. GUI replies:

I have been asked to include more obscure and really amazing questions. This one really fills the bill. However, before you question the usefulness of this question, consider that it will likely save at least one company from totally hitting the skids, laying off all employees, and filing Chapter 11.

MFC30.DLL can be used (directly or indirectly) only from Microsoft Foundation Class Library (MFC) applications. That means that an OLE control (.OCX file) cannot use MFC30.DLL or any dynamic-link library (DLL) that uses MFC30.DLL, since there is no guarantee that the application that is using the OCX is an MFC application using MFC30.DLL.

Using OC30.DLL in your DLL instead is okay, but be sure to compile with _AFXCTL instead of _AFXEXT.

In addition, be sure to set up the right module context in your DLL. Here is the code from OCD30.DLL (which contains the database classes for OCX controls) from MFC 3.1.

extern "C" BOOL WINAPI
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
   if (dwReason == DLL_PROCESS_ATTACH)
   {
      // NOTE: Important call to _AfxSetCurrentModuleTlsIndex.
      _AfxSetCurrentModuleTlsIndex(NULL_TLS);

      // Call DisableThreadLibraryCalls if available.
      BOOL (WINAPI* pfnDisableThreadLibraryCalls)(HMODULE);
      HMODULE hMod = GetModuleHandleA("KERNEL32.DLL");
      ASSERT(hMod != NULL);
      (FARPROC&)pfnDisableThreadLibraryCalls =
         GetProcAddress(hMod, "DisableThreadLibraryCalls");
      if (pfnDisableThreadLibraryCalls != NULL)
         (*pfnDisableThreadLibraryCalls)(hInstance);

      // Shared initialization.
      if (!AfxInitExtensionModule(extensionDLL, hInstance))
         return FALSE;   // failure

      // Wire up this DLL into the resource chain.
      // (In the Win32 version it is OK to create this in DllMain.)

      CDynLinkLibrary* pDLL = new CDynLinkLibrary(extensionDLL);
      if (pDLL == NULL)
         return FALSE;   // failure
      pDLL->m_bSystem = TRUE;

      // NOTE: Important call to AfxPopModuleContext.
      // Save a copy of our module data for later use.
      AfxPopModuleContext(NULL, TRUE);
   }
   else if (dwReason == DLL_PROCESS_DETACH)
   {
      TRACE0("OCD30D.DLL Terminating!\n\r");
   }
   return TRUE;    // ok
}

Doing something similar in your own OCX extension DLL should eliminate your memory leak.


Backtalk: A Continuing Dialog on the Development Library and Platform

Melinda Hohlbein

May 9, 1995

Miss me? I'm not out there yakking with you all online right now because I had a baby. And you know, a total stranger had the nerve to ask me if it hurt. Yeah, it hurt. Go pass a kidney stone while undergoing abdominal surgery—without anesthesia—and having your fingernails pulled out with pliers and then we'll talk. Of course, the baby is kind of cute.

But back to business.

An individual—with clearly too much time on his hands—wrote to us recently and recommended that I put more "personality" in my writing. Note he didn't mention my personality, just more personality. Really? Okay, but I couldn't find a place to put unmentionable phrases in any of these sections, so my shameless display of character will have to wait until the next issue.

Speaking of character, we had some lively and wholly unmedicated ones write in these past few months demanding that we address their concerns. Read on to find out the sordid details. I know you're breathless.

Browser: The next generation

The demands are already rolling in for the next generation of the browser software employed by the Development Library CD-ROM. We're planning to release it sometime later this year. (Is that vague enough?)

I asked Bill Shelby—browser team developer extraordinaire—to give us some hints about what we can expect in the next version of the browser. Here's what he said: "We came up with a fix that allows you to search and find anything by just thinking at the Find dialog box, and we tripled the capacity of the disc, but we accidentally formatted the drive with some (not backed up) source code when we really needed more disk space for something else."

You see what I have to work with. Thanks to all of you who have sent in suggestions about the Library—keep 'em coming, please.

Get FAQ

Abel Watchford of Cranston, Rhode Island, writes: "You must get asked this all the time, but what..."

Abe's question isn't the issue here, but he raised a great point. Why don't we have a central location for answers to common questions (technical and nontechnical) about the Developer Network? Abe, Abe, buddy, it exists. The Developer Network frequently asked questions (FAQ) help and text files are ready and waiting for you to download from the following locations:

• ftp microsoft.com: /developr/msdn/faq

• CompuServe: GO MSDN, Library 1

• Here on the Internet OffRamp, under Developer Information: http://www.microsoft.com/pages/developer/msdn/
offramp/msdninfo/msdnfaq.htm

• The Microsoft Network: open Categories/Computers & Software/Software/Microsoft/Microsoft Developer Network/Library Sampler or Platform Overview

Plug me into Windows 95

Eric Baird, of a town that shall remain nameless, espoused to us the virtues of a "one-stop notice board for official Windows 95 status updates."

Can you say WinNews? Sure, I knew you could. Here are your options:

• E-mail: to subscribe to WinNews, send mail to enews@microsoft.nwnet.com with the words SUBSCRIBE WINNEWS as the sole text of your message

• WinNews Servers: on the Internet, use ftp or the World Wide Web: ftp://ftp.microsoft.com/PerOpSys/Win_News, http://www.microsoft.com

• The Microsoft Network: open Categories/Computers & Software/Software/Microsoft/Windows 95/WinNews

• CompuServe: GO WINNEWS

• Prodigy: JUMP WINNEWS

• America Online: keyword WINNEWS

• GEnie: download files from the WinNews area under the Windows RTC

Don't be shy. Send your comments, suggestions, grievances, and moans to us at one of the addresses show below. Oh, yeah. It was a "he" and he tipped the scales at 9 pounds, 9 ounces. We call him Mitchell.

To send us your comments, please use one of the following addresses:

Internet:
msdn@microsoft.com
CompuServe: >INTERNET:msdn@microsoft.com

Mail:
Microsoft Developer Network
One Microsoft Way
Redmond, WA 98052-5399

Fax:
(206) 936-7329
Attn: Developer Network

There is no truth to the rumor that Microsoft has bundled Melinda Hohlbein into an online information and support product.


Basic Principles: Getting the Most from the Data Access Object Layer

Robert Eineigl

May 9, 1995

In the last Basic Principles column ("Tips and Tradeoffs in Data Access Performance," March 10, 1995), I discussed three of the four major design choices a data-access client application programmer must make when using Visual Basic:

• Which back-end relational database to use

• How to choose the data-access method

• Design of the back-end database system

Now I'll cover a top-ten list of performance enhancements when using the Visual Basic and Microsoft Access data-access object (DAO) layer.

Before considering the list, it's important to note that the latest version of the Microsoft Access engine (2.0) is mandatory for best performance, because the Jet 2.0 engine (hereafter referred to as Jet) provides the Visual Basic DAO.

This article focuses on maximizing DAO performance when accessing remote databases, such as SQL Server, as opposed to ISAM (indexed sequential access method) databases, such as Microsoft Access, dBASE, Paradox, FoxPro, and Btrieve.

Because Jet relies on the open database connectivity (ODBC) protocol to access remote databases, using the DAO inefficiently can limit its ODBC performance capability and cause dramatic performance hits. As with any data access method, there is no substitute for efficient use of the DAO.

#1. To attach or not to attach

The greatest single performance enhancement you can make to a Visual Basic ODBC application is to attach the tables in an ODBC database to a local Microsoft Access database so that Jet stores field, index, and connection information for the remote tables. Now when you access the tables, the engine doesn't submit repeated redundant queries to the system catalog procedures on the server to verify this information.

If the structure of the attached table changes, you will need to reattach the table. This can be done on the fly, in code, in response to a trappable error. If you use attached tables, the Jet engine automatically connects to the server when you open the local Microsoft Access database. You can then create snapshots or dynasets on the attached tables.

#2. Which DAO object?

The DAO layer in Visual Basic provides great coding leverage, if used efficiently. To access remote databases through ODBC, two kinds of recordsets are provided: dynasets, which can be updated, and snapshots, which cannot.

If you don't need to update data and the recordset contains fewer than 500 records, a snapshot can reduce the time to open the recordset.

Because the data contained in each row is fetched for a snapshot recordset, you can further minimize the performance hit by ensuring that you return only the columns you need.

If, however, the recordset is large or contains fields of the DB_LONGBINARY or DB_MEMO type, using a dynaset is more efficient, because fetching keys (and data only as needed) requires fewer local resources than actually fetching all the data. When you open a dynaset, Jet retrieves only the primary key of each record, whereas a snapshot retrieves the entire record.

Although the CreateSnapshot statement by itself returns faster than the CreateDynaset statement, fully establishing set membership with a large result set, by executing a MoveLast on both objects, will take longer on the snapshot object than on the dynaset object. Instead of transferring the data in each column of a row during the fetch, Jet builds a dynaset by fetching just the key values that uniquely identify each row. This is why an ODBC table must have a unique index to be updatable. Using key values speeds the chunking operation and minimizes network traffic, especially when browsing large tables.

If you need only to append data to an ODBC table, open the dynaset with the DB_APPENDONLY flag. This will avoid populating the dynaset with the keys/bookmarks of all the records in the table. If you're trying to append a lot of data to an ODBC table already stored in an .MDB table, wrap the inserts with transactions.

#3. Use transactions

A transaction is a set of operations considered as a single unit. A transaction is saved (committed) only if all the operations succeed. If any operation fails, all successful operations are rolled back (canceled), and the data is returned to its previous state.

Transactions are a powerful way to improve performance as well as multiuser concurrency. Using transactions allows Jet to buffer operations and then commit the changes in a single batch. This saves disk I/O and/or network packets.

On most servers, transactions generate locks that prevent other users from updating or even reading data affected by the transaction until it's committed or rolled back, so keep transactions as short as possible. Avoid beginning a transaction and then waiting for the user's response before completing it.

When using "bulk operation" SQL statements, such as UPDATE, INSERT, and APPEND, Jet places a transaction around the operation. This is necessary because one Jet SQL statement may actually correspond to many server statements.

If the server supports transactions at all, Jet assumes only single-level support, that is, no nesting of transactions. Therefore, if your Basic code nests transactions, only the outermost BeginTrans, Commit, and Rollback are actually sent to the server; nested transaction methods are ignored.

Jet often conserves connections by sharing them between queries. If you use server-specific transaction commands in passthrough queries, they can confuse the internal tracking of server transactions performed by Jet, as well as give you unexpected results. Instead, use the native BeginTrans method. Jet translates these transaction methods into the equivalent server commands.

#4. To passthrough or not passthrough

The DB_SQLPASSTHROUGH flag is an option when connecting directly to ODBC databases. Using this flag with the CreateSnapshot method tells Jet to ignore parsing the SQL statements and pass them through to the ODBC driver and, ultimately, to the database for parsing and execution. Because the result set from a query passed through to the back end is not updatable, the set is fetched into a general buffer and accessed with local pointers.

Use the ExecuteSQL method when executing bulk operations for a greater performance gain for action queries such as updates. This passthrough method allows the use of the thinnest possible DAO layer and, if used for operations that the Jet optimizer may handle inefficiently, offers an alternative that depends strictly on the server's optimizer. To create a passthrough query, you must know the SQL syntax supported by your server. Reusing a single snapshot object, with the passthrough flag set, allows a continuous session of native back-end syntax, including native transaction syntax, to be sent to the back end, bypassing the DAO while retaining its ease of fetching result sets.

#5. Set versus row processing logic

Processing rows in a While or For loop, even if wrapped in a transaction, is usually slower than letting Jet or the ODBC server use the set processor in its SQL engine. For example, updating one row at a time within a code loop is a common practice in programming to ISAM databases. With the appropriate conditions specified in the WHERE clause, a single SQL update statement could replace the loop and enhance performance.

#6. Use the Refresh method sparingly

The Refresh method is generally an expensive operation relative to most DAO operations. Basically, it involves recreating all the collections in the DAO object. DAO has many collections on its various objects, and a DAO collection can get out of date if someone else makes schema changes to the database. The Refresh method of each collection forces DAO to fill the entire collection again with the latest information in the database, and is generally only useful for rarely run utility programs that modify or examine database structures.

#7. Use parameterized queries

You can use QueryDef objects stored in the local Microsoft Access .MDB file to perform SQL queries on attached ODBC tables, or you can create QueryDefs that accept parameters analogous to stored procedures on SQL Server. A common requirement of applications is to build an SQL string based on values that the user provides. While this can be done dynamically, by building on the fly an SQL statement combined with input variables, it isn't efficient.

The alternative is to create parameterized queries that have variables in place of the actual values in the SQL statement. A saved and compiled parameterized query can reduce the steps Jet needs to perform queries to four:

1. The parameterized query is sent to the ODBC server.

2. The server parses and compiles the SQL string.

3. Jet passes the values for the parameters.

4. The ODBC server retrieves the results and returns them to Jet. Successive queries with different parameter values further leverage the server's compilation.

#8. Use the SQL WHERE clause instead of Find methods or the Filter property

Using the SQL WHERE clause instead of the native Find method can be much faster, especially against ODBC databases. The SQL query can then be optimized by the ODBC server and return just the row(s) requested, rather than having Jet search through its entire membership of keys looking for rows that match the criteria.

Similarly, the appropriate SQL WHERE clause can replace the Filter property. Also, replacing a Sort property with an SQL ORDER BY clause in a query allows the server to do the work and return the data in the order requested. Running this new query will be faster than recreating a new recordset. As a general rule, don't use the Sort property on any set of rows that has more than 100 records.

#9. Use Bookmarks versus the Find method

Bookmarks correspond directly to the unique keys for a table. The fastest way to return to a record is to store its bookmark. The memory overhead in storing the string for the bookmark is far less than the execution time involved in using the Find method.

#10. Use SQL joins versus multiple DAO objects

Rather than concatenate values from multiple dynasets created from individually attached tables in code, it is far more efficient to use Jet's capability as an SQL engine to join the attached tables in a single additional dynaset. This may seem obvious, but the temptation to use multiple data controls for simplicity of data entry sometimes leads programmers to use code to do all the work to browse the results, instead of simply employing an SQL join.

Robert Eineigl works in Microsoft's Information Technology Group. His nocturnal interests include bicycle design, keyboard improvisation, and wildlife serenades with his custom-made trumpet.

More Reading

The Developer Network Development Library has numerous articles on database programming, including:

• "Jet Database Engine ODBC Connectivity" by Neil Black and Stephen Hecht. This describes in great detail how Jet uses ODBC to retrieve server data. This is required reading for anyone using DAO to write significant server applications.

• "ODBC: Architecture, Performance, and Tuning" by Colleen Lambert. This paper provides a good overview of how ODBC works, and addresses performance issues in a realistic and useful fashion.

Some of these are also available directly from Microsoft, usually from one of its download services, such as the Internet server at ftp.microsoft.com.


Can Johnny Come Out to AutoPlay?

Windows 95 executes your application off a CD-ROM

Robert Hess

May 9, 1995

OK, picture this. You are sitting at your computer and suddenly get the itch to play a game. You have the latest CD-ROM version of <your favorite game>, and you push the disc into your CD-ROM drive. What is the next thing you want to do?

Simple. Play the game. What steps are necessary to do this? Not so simple. Depending on exactly how the CD-ROM and its application were designed, you may face such instructions as:

1. Insert the CD into your CD-ROM drive.

2. With Windows running, from Program Manager, select the File menu, and then the Run command.

3. In the Run dialog box, either type the full path of the application to run (d:\game\full\game.exe, assuming that your CD-ROM drive is the D drive; enter the appropriate drive letter if your CD-ROM drive is located elsewhere) or click the Browse button and navigate your way to the GAME.EXE application.

Since one of the primary goals of Windows 95 is "Make it easy, not just easier," this is obviously an aspect of the system that could vastly improve. To make this "easy" you want the game to start automatically when you insert the CD. On Windows 95, this is exactly what can happen.

A new feature, AutoPlay, allows Windows 95 to automatically start your application off a CD-ROM as soon as the disc is inserted into the drive. It makes playing a CD-ROM–based game on Windows 95 as easy as playing a game on a standard cartridge-based game system.

Implementing AutoPlay support

If you are developing an application to be distributed on CD-ROM, you should seriously consider adding AutoPlay support to your disc. It doesn't require any programming knowledge or changes to your application, and it is completely backward compatible with any system on which your CD-ROM currently runs.

All you need do to implement AutoPlay on your CD title is add a file named AUTORUN.INF to the root of your CD-ROM drive. When the CD is inserted into the drive, the system automatically looks for this file and follows the instructions in it.

The format of AUTORUN.INF is similar to a standard .INF or .INI file, with a section name (enclosed in square brackets) followed by keywords and values on subsequent lines. A minimum AUTORUN.INF file would look like:

[autorun]

open = filename.exe

In this example, autorun is the required section name; open is the keyword the system will seek to determine what action to take when the CD is inserted; and filename.exe is the application that will be started.

A fully configured AUTORUN.INF file might look like:

[autorun]

open = filename.exe /switch1 /switch2

icon = filename.exe, 1

shell\configure = &Configure

shell\configure\command = setup.exe /config

shell\install = &Install

shell\install\command = setup.exe

shell\readme = &Read Me

shell\readme\command = notepad

help\readme.txt

shell\help = &Help

shell\help\command = help\helpfile.hlp

In addition to automatically launching filename.exe, the above example will add two command-line parameters, /switch1 and /switch2, when the application is run. The actual command-line parameters to use, of course, depend on what the application being launched accepts. When the drive is viewed in the Explorer (a Windows 95 navigational tool that replaces Program Manager and helps you locate files and information), the second icon in the executable's resource will be used in place of the normal CD-ROM icon (icon references are zero-based). If you would rather access the icon by its ID, simply use the negative ID value.

When the user clicks the icon with the right mouse button, four new items can appear—Configure, Install, Read Me, and Help—in addition to the normal context menu items. The user clicks the menu item to run the associated command. These menu items are used for illustration only, and are not intended as a recommendation of menu items you should add for your application. Please refer to the Windows User Interface Design Guide for Windows 95 to determine the best menu items to add for your application.

Suppressing AutoPlay

For those times when the user doesn't want to use AutoPlay when inserting an AutoPlay-enabled CD-ROM, it can easily be suppressed by holding down the SHIFT key while inserting the CD.

AutoPlay style guidelines

While there isn't yet much in the way of style guidelines on implementing AutoPlay, here are some general rules of thumb to consider:

• Whatever you do, do it quickly, then stand back and let the user drive. Promptly give the user input on his or her wishes, whether it's to run the application, access some data, or do an about-face and exit.

• Use a minimum of hard-disk resources; run completely off the CD if at all possible.

• If there is a performance benefit in loading some data onto the hard drive, let the user select this option.

• If data is moved to the hard drive, have it removed upon exiting.

• If the application can be fully installed to the hard drive, provide this as an option to the user. But provide the option to fully remove it from the hard drive as well.

Further information

A very simple application illustrating how an AutoPlay-enabled application might be implemented—"Building AutoPlay-Enabled CD-ROM Titles and Games" by Alex St. John and Jeff Camp—can be found in the Technical Articles section of the April release of the Developer Network Development Library. It takes a very simple application and, rather than running it directly when the CD is inserted, runs a 'launcher' application that quickly allows the user either to launch the application or exit.

Robert Hess works in the Developer Relations Group, where he spends his time huddled behind several computers, trying to influence application developers worldwide.


Case Study: Business Solution Has Pet-Hospital Startup Purring

Martha Maroney

May 9, 1995

In the world of small-animal veterinary medicine, Dr. Scott Campbell has learned that it's smart to think big. Building on the success of his small-animal veterinary practice in Portland, Oregon, Campbell has developed a rapidly growing collection of pet hospitals in Oregon, California, Washington state, and the Chicago area. These VetSmart Pet Hospital & Health Centers, which offer a full range of veterinary services, are managed entirely through a client-server solution based on the Microsoft BackOffice product family.

When Campbell first pursued the VetSmart idea in 1993, he opted to establish pet hospitals at a number of the nationwide PETsMART superstores. Initially he planned to open 60 hospitals, with each eventually employing six veterinary doctors and 30 support staff.

For such an ambitious venture Campbell knew he needed a comprehensive software solution, one that would effectively automate the systems he had developed at his Portland pet hospital over an eight-year period. As Campbell envisioned it, the VetSmart solution would have to support the quality care, customer convenience, and efficiency that had made his Portland facility successful. It would have to help implement his goal of an essentially paperless office. It also would have to ensure the planned hospitals' compliance with a stringent set of medical, legal, accounting, and quality-assurance requirements.

In addition, the VetSmart solution would have to fit smoothly into a clinical environment, offering familiar interfaces to users ranging from doctors to lab technicians to receptionists, and processing information directly from such sources as stethoscopes and electrocardiogram (ECG) devices. Finally, it would have to act as a marketing tool by educating pet owners about the importance of vaccinations and other veterinary services, a function requiring various media and input/output capabilities, including touch-screen, video, bar coding, sound, and multimedia.

A natural migration to Windows

After launching the development effort, Campbell formed a company called Medical Management International (MMI) to manage both development of the software and the VetSmart pet hospitals, and enrolled the company in the Microsoft Solution Provider program. He was joined at MMI by Mark Howard, a FoxPro database expert and president of Vancouver, Washington-based Software Blueprints, itself among the first members of the Microsoft Solution Provider program.

Howard was familiar with Microsoft products, having programmed in FoxPro and before that FoxBASE for more than a decade. "I had a strong relationship with the Microsoft technical support people, starting with the formation of my business back in 1983," Howard explained. "Whatever the question, I knew we could count on receiving a timely and complete answer." He decided to base the VetSmart solution on FoxPro for Windows and other Microsoft tools.

FoxPro under pressure

With the first VetSmart hospitals scheduled to open in spring 1994, development proceeded rapidly. To create a solution that would eventually total a half-million lines of code, a team of 20 to 25 developers and testers worked 70-hour weeks. Howard himself put in even longer hours. "At times the pressure was so intense it felt like an inferno," he recalled. "When we talked about putting out fires, we felt like we really meant it."

Howard took advantage of such FoxPro tools as Screen Builder, Program Manager, Report Writer, and Query Builder. "Along with FoxPro's English-like language, these tools enabled us to manipulate things very quickly," he said. One advantage was the FoxPro approach to events and methods. "Although you can define fewer events and methods than you can in C++, in FoxPro they're very generic and extendible, so you can do a lot with them."

Although the developers used FoxPro for most of their programming, they also added some code using OLE and the Microsoft Foundation Class Library (MFC) in the Visual C++ development system. Visual C++ provided specialized capabilities, including support for an integrated ECG device. Using a dynamic-link library (DLL) created with Visual C++, the developers were able to speed up the refresh of critical screens. The relative ease of using MFC also proved handy. "Since I'm not ordinarily a C++ programmer, I wouldn't have been able to use the language at all without MFC," Howard said.

Building atop existing applications with OLE

OLE played a major role as well. "OLE helped us build on top of existing applications so we didn't have to develop them from scratch—an absolute necessity considering our schedule," Howard pointed out.

Using OLE to export data from Microsoft Excel into Microsoft Graph, for example, the developers built a sophisticated performance-analysis application. By exporting similar data into Word, they constructed a peer-review application, and by trading data between Word and a specialized vertical product, they incorporated powerful quality-control functionality into the solution. Because the Visual Basic for Applications programming system was not available at the time, the developers implemented these communications through dynamic data exchange (DDE).

Office with Windows

For the foundation of the solution, Howard selected Windows NT and Windows for Workgroups as operating systems. "We wanted the ease of use and administration we knew we would find only in a Windows-based approach," Howard explained. "More important, we wanted a system that was designed from the ground up to meet the integration needs of a major client-server solution, and Windows NT met those requirements on the nose."

Microsoft Office Standard Edition provided desktop-productivity tools and components of key applications, and two new products were added when they became available in early 1994: remote mail, for interhospital communication, and the messaging application programming interface (MAPI), for the electronic-mail interface. With remote mail and the remote access service (RAS) available through Windows for Workgroups, the developers built a powerful set of interhospital communications, not only for e-mail but also for remote administration and daily backups. MAPI supported a programmatic interface to Microsoft Mail—which turned out to be a crucial advantage, according to Howard. "Thanks to MAPI, I was able to build the communications set with minimal coding," he said.

From medical records to inventory

In March 1994, developers released the first version of the VetSmart solution and within six weeks installed it in six new VetSmart pet hospitals. Today, the solution is running in more than 40 VetSmart facilities.

Known as PetWare, the solution incorporates more than 600 screens. On the medical side, it streamlines record entry and management, diagnoses and therapeutic protocols, vaccination history and results, prescriptions, and laboratory record keeping. For each hospital's management, it helps track team assignments and staff performance. Administratively, PetWare supports revenue accounting, invoicing, and inventory management. For marketing, it provides educational handouts and videos, which are played for clients in the exam rooms.

The PetWare server workstations run Windows NT Server, while its client workstations run the Windows for Workgroups operating system. A documentation workstation and a helpdesk workstation run Windows NT Workstation. At each pet hospital a FoxPro database of more than 100 MB provides PetWare's main data engine, which can be accessed by as many as 20 people almost continuously. "There's nothing faster than FoxPro's Rushmore technology for lookup, which is mostly what we do," Howard said. "Users consistently report instantaneous data access."

RAS, in addition to supporting e-mail, provides remote administration of the hospitals' servers and local area networks (operating through NetBEUI protocols) from the MMI office in Portland. "NetBEUI is transparent, reliable, and flexible, and RAS is fantastic for the complete level of control it gives us," Howard said. "In particular the Windows NT command prompt gives us much-needed control over such tasks as monitoring error logs and nightly backup, both critical for meeting the stringent redundancy requirements in the veterinary profession."

The Windows NT scheduler component provides additional network administration services by enabling administrators to schedule software installation, backups, file updates, and other tasks remotely. "With the scheduler we save time, money, and headaches by avoiding all those hours we might otherwise spend on the phone," Howard noted.

Automating remote administration

Immediate plans for PetWare include upgrading all the developer workstations to Windows NT Workstation. Once that happens, administrators will use the Microsoft Systems Management Server, another component of the BackOffice product family, to completely automate remote administration.

In other areas, developers will upgrade the central database engine with Visual FoxPro version 3.0. After that they may replace the corporate data repository, now in a FoxPro database, with SQL Server. Making this possible will be the Visual FoxPro 3.0 direct-command capabilities for SQL Server, which will enable FoxPro to act as a front end to a SQL Server database. "We believe SQL Server can give us even greater data integrity and more secure transaction rollbacks and central storage," Howard said.

According to Howard, a number of major pet-food and pharmaceutical companies have expressed interest in using VetSmart data for research and new-drug trials. "Since these businesses are SQL-oriented, a Microsoft SQL Server platform could make our data much easier for them to access," he said.

An indispensable role

According to Campbell, PetWare plays an indispensable role at VetSmart. "Without PetWare we wouldn't be able to offer the high-quality, consistent, and cost-effective care that's required for a venture of this scope to succeed," he said. "We simply couldn't have created this business without it."

Current plans call for VetSmart hospitals in 120 locations by the end of 1997. As Campbell explained, "The continuing expansion of VetSmart is likely to make it the most visible veterinary practice in the United States and the one by which people judge the whole profession." With PetWare supporting the hospitals' operations, he welcomes the increased visibility. "We're adamant about raising standards, doing the best we can by pets and their people, and helping the profession in general," he said. "Using PetWare, I'm confident we can keep on doing these things."

For more information

For more information about Microsoft products, call the Microsoft Sales Information Center at (800) 426-9400. In Canada, call the Microsoft Canada Customer Support Centre at (800) 563-9048. Outside the United States and Canada, please contact your local Microsoft subsidiary.

Martha Maroney is president of Trimar Communications, a Portland, Oregon-based company serving software manufacturers and other high-tech businesses.


CompuServe Adds Value to Your Apps

May 9, 1995

In an age of application suites, groupware, and software bundling, what can increase the connectivity and data-acquisition capability of smaller applications?

One answer is to include application extensions in an extensive online environment such as CompuServe. Although the Developer Network has long had a presence on CompuServe, many developers may not have considered adding connectivity to CompuServe to enhance their applications. An online service can add value to most applications in numerous ways, such as the ability to obtain stock quotes for a financial application or to gather news stories for a personal information manager.

CompuServe offers two simple ways to add this connectivity to your applications without having to write an online interface from scratch.

The first is the CompuServe Communications Toolbox (CCT), a set of tools utilizing CompuServe's Host Micro Interface (HMI) that allows developers to build micro applications for connecting to the CompuServe Information Service (CIS). Although the Toolbox's primary function is to enable micro applications to establish HMI sessions with CIS through the connect functionality of CCT, it can also be used simply to access any host on the CompuServe network.

The second is the CompuServe Multimedia Publisher Partnership Program, which allows developers of multimedia CD-ROM products to add value to content by integrating their CD-ROM with access to the CIS.

CompuServe Communications Toolbox

By utilizing the CCT, a developer can interact with CompuServe in a defined, predictable manner. The underlying HMI protocol the Toolbox uses presents application protocols to all CompuServe host applications, such as forums or e-mail.

This protocol uses a structured data format, with an error-checking transport layer, to present the micro application with information that can be handled directly from within your existing user interface. This interface control flexibility means that you don't have to redesign the look and feel of your project to accommodate this new functionality. The CCT also provides the necessary low-level interaction for an application, so that everything from memory allocation and serial communications to data validation can be accomplished directly with a call to the Toolbox.

Many performance and compatibility requirements were incorporated in the design of the CCT. The Toolbox itself is fully ANSI-compatible, C++ callable, and compiled in various combinations of environments, compilers, and memory models.

Wherever possible, dialog boxes give a standard user interface to the Toolbox. Functions and dialog boxes are provided for obtaining serial communications settings, which consist of hardware parameters and a modem database to select parameters, as well as status boxes for displaying messages sent from the Toolbox.

These dialog boxes work in conjunction with CompuServe's predefined settings file format for common file access among multiple CompuServe applications. This file is used by all CompuServe applications to store the communications parameters that allow them to connect to CompuServe. If a function is platform-specific, the supported platform is listed in the declaration of the function.

Using the SendMessage function allows multitasking environments, such as Windows, a native way to interact with the Toolbox. In environments such as MS-DOS, the SendMessage function provides a single interface for the many functions in which the Toolbox must interact with the application.

The Toolbox also allows multiple applications to access it simultaneously. In the Windows environment, this means that all applications using the Toolbox can share a single dynamic-link library (DLL) without chance of interference. (In environments other than Windows, this may not be a requirement of the application.)

Because the library can be shared at run time in some environments (for example, Windows), a numeric naming scheme for the Toolbox is used that allows CompuServe to guarantee compatibility between new releases of the library. If at any point the libraries become incompatible with the previous version, the numeric portion of the filename will change (for example, CCT110 might supersede CCT100).

Hot links for multimedia

The new CompuServe Multimedia Publisher Partnership Program lets multimedia developers add various capabilities to their applications without increasing development time. The program permits inclusion of hypertext documents that link to various CIS locations.

It also allows users to perform such actions as electronic registration and transaction processing, and even to use CompuServe as a vehicle to communicate with their company for support. This gives the normally static medium of CD-ROM a new kick. The links can be used for something as simple as a weather report or for something more intensive, such as a downloadable patch or update area.

You can even use these hypertext links to Internet services through CompuServe. As part of this program, you can also license customized versions of other CompuServe software products, such as WinCIM or MacCIM, to include on your CD-ROM. (WinCIM is an application that serves as a graphical front end to CompuServe. WinCIM provides icons that let users jump easily and quickly into the developer-related areas of the Microsoft Connection area on CompuServe.)

Further information

The CCT and CompuServe Multimedia Publisher Partnership Program are both available for developers on the Windows 3.x, Windows for Workgroups 3.x, MS-DOS, GEOS, and Macintosh platforms. Support for Win32 development is planned this summer. For information about these or other CompuServe developer programs, contact:

Brian Glowacki
Phone: (614) 538-3379
Internet: glow@csi.compuserve.com
CIS: cis:glow

The Developer Network Development Library includes information on joining the CompuServe Information Service. For more information on CompuServe, call (800) 848-8990 from within the United States, or (614) 529-1340 outside the United States.


Deep C++: Nine Great Debugging Tips for Visual C++ 2

Deep C++: Nine Great Debugging Tips for Visual C++ 2.0

Rico Mariani

May 9, 1995

Here's a list of tips you might find handy when using the Microsoft Visual C++ development system. Although this list is geared toward Visual C++ version 2.0, some of the tips apply to previous versions as well.

Hopefully there's something here that will enable you to become a bit more productive. Much, if not all, of this is documented elsewhere, but with such a complex product it's no wonder that not everyone finds every piece of information.

So in no particular order...

1. That edit item on the toolbar is really handy

You can do all manner of cool stuff from the toolbar. In fact, most commands that work on the current word or selection also work up there. For instance, to get online Help for an API name, put the focus in the edit control on the toolbar by using CTRL+F or clicking it. Type the name of interest, and press F1.

The fun doesn't stop there. You can also browse to definitions or references of a symbol by pressing F11 or SHIFT+F11, respectively, or use any of the browse queries by pressing the appropriate button. You can set a breakpoint by pressing F9. There's also QuickWatch (SHIFT+F9) to quickly see the value of an expression. This works even if you're not debugging, so you can use it as a quick calculator.

Of course, the original function of the edit control was to do searching, so F3 (search) works as well. The edit control is like a mini command window.

2. You can type in the darndest places

There are some not-so-obvious items that are fully editable. For example, the Watch window lets you edit the value of variables, as does the Locals window. The Memory window lets you type in the address field to set a new viewing location (if you know this you can turn off the toolbar and get a little space back), and you can type in the display area to edit the bytes or words you're viewing.

All of these windows are fully functional text windows, so you can copy their contents to the Clipboard and paste them in a spare document for later comparison. Ditto for the Call Stack and Disassembly windows.

3. You can do more stuff in that Call Stack window...

Call stacks aren't just for looking at. You can use F9 to set breakpoints on places you'll return to (this is great for setting a safety net of checkpoints), or you can use F7 to run until you return to a particular frame. You can also copy and paste the call stacks if you want.

Generating a call stack is computationally quite expensive, so keep the window up only when you need it or keep it small so that just a few frames need to be computed. Otherwise you'll significantly slow down single-stepping. The little Call Stack dropdown in the Locals window isn't as loaded with goodies as the Call Stack window, but it takes up only a little space and lets you change frames as easily as you could with the old Call Stack menu in CodeView.

4. Debuggers can drag and drop, too

You can save yourself a lot of typing with drag and drop. For example, drag from the source window to the Watch window to add watches. Drag from the Watch window to see the value of a variable as memory. Drag the address that a pointer points to in order to see it as memory. Drag a function name into the Disassembly window to see the function's code.

People often drag a pointer variable into the Memory window to see what it points to. They are then confused because Visual C++ shows the pointer variable itself instead of what the pointer points to. You can avoid this problem by dragging the value of the pointer instead of the pointer variable.

5. QuickWatch does more than just watch quickly

Because QuickWatch is a modal dialog box, it is possible to do a couple of useful things that don't work in the Watch window:

• You can evaluate an expression that includes a function call. This is a great way to get your application to help you debug it. Write some useful dumping functions that use OutputDebugString to emit information about your program, and then call those functions from the debugger.

• If you are looking for a pointer to a C++ class, the debugger will automatically show you the actual type of the class. For instance, if you have a CWnd* and the CWnd is actually a CListBox (a class derived from CWnd), this will be indicated in the window by an extra item that you can expand to show the members of CListBox. In many cases the actual type of the class is even more important than the data members.

The default accelerator for QuickWatch is SHIFT+F9. Don't forget that you can type expressions in that little edit item and then watch them. The thing I "quickwatch" most often is "this", so I can see the derived-most type.

6. Play it again (or not), Sam

A classic problem is stepping one statement too far (usually over a function call). You can easily move the extended instruction pointer (EIP) where you want it by using the right mouse button to click the source line and then choosing Set Next Statement from the pop-up menu (or use the keyboard to move the cursor to the line and then press CTRL+SHIFT+F7).

In addition to seeing a function call a second time, you can force the debugger to step out of a function without running it all by moving the cursor to the ending curly brace ( } ). Or you can skip over code that is faulting to let you back up a frame or two to the real source of the problem (so that maybe you can repeat a call up there!). Also, you can often rerun a loop if you also run the initialization step.

If you try to move the EIP out of the current function, you'll be warned that this probably isn't a good move (the stack is likely to be messed up, no destructors will be run, and so on), but sometimes even this can be useful. For example, if you know your state is already trashed and you won't be able to proceed, moving the EIP to another function probably won't make things worse—and might give you access to some interesting data.

7. Where's the remote?

Remote debugging is back with Visual C++ 2.0, and you no longer need a Ph.D. to configure it correctly. In fact, now it's very simple to get it working. Microsoft currently supports only serial communications on the Intel platforms, but even at 57600 baud it's not always as fast as you might like.

Here are two important tips to improve your performance:

• Try 38400 baud. (I'm serious.) Depending on how long the cable is, and how fast your machine is, you might get so many additional transmission errors sending at 57600 baud that you'll actually be faster at 38400.

• Keep the Call Stack window closed when you don't need it. Having lots of watches or a giant Memory window will cause the transmission of a whole lot of data. But the Call Stack window, which looks really small and innocent, also transmits a bunch of information when remotely debugging.

Still, remote debugging is a great way to get around problems where having the debugger and the "debuggee" share the same keyboard or monitor makes it impossible to create the problem scenario. Remote debugging also makes it possible for you to get a debugger on a system where the whole integrated development environment (IDE) might not fit.

8. There's a browser toolbar, y'know

When using the browser, turn on the browser toolbar. It's the best way to get at the browser queries. Check out the ToolTip for each button (move the cursor over the top of the button) to see what it does, then click what you want to browse and click the appropriate button on the browser toolbar. Don't forget that you can browse from the toolbar edit item. Try putting wildcards in there and then doing browser queries—my favorite is doing a file outline on *.CPP. My second favorite is doing a goto definition on CMyClass::On* to see all the message handlers I've defined for my class.

I don't want to turn this into another big file that nobody reads, so I'll end with...

9. Sometimes the spot isn't marked by X

Plenty of thought went into making the IDE a productive place to work with easily found features. The number of functions, however, in modern development environments is comparable to any major application, and their features simply can't all fit on the main menu. Take some time to check out the pop-up menus and the toolbars, drive through the options pages, and look at the property pages. You'll be pleasantly surprised by something. I'm just sure of it.

Rico Mariani was the development lead for the debugger and the browser on Visual C++ 2.0. He has worked on Microsoft development tools since 1988 and has by now touched just about all the tools.


Developer Roadmap Provides Sales Info on CD

May 9, 1995

Microsoft has prepared a comprehensive CD catalog of all its products and services for software developers. The Microsoft Roadmap to Developer Products and Services is now available—at no charge—to Developer Network members and nonmembers alike.

The Roadmap CD contains more than 100 files of sales information on Microsoft development tools, operating systems, and services for developers, including white papers, data sheets, evaluation guides, Q&As, strategy papers, technology specifications, and product demonstrations. Among the latter are demonstrations of Visual C++, Visual Basic, and Fortran POWERstation, as well as the Developer Network Development Library and Development Platform.

The Roadmap is intended to provide a one-stop, easily searchable source of product and service shopping for developers, and does not contain in-depth technical information.

The CD offers a browser and full-text search capability. A directory of Microsoft sales and product-support telephone numbers is included. Plans call for the CD to be updated quarterly.

It can be ordered by any of the following methods:

• Call the Developer Services PhoneFax Server at (206) 635-2222. Order document 170.

• Access the Developer Roadmap order form in the Microsoft Library on CompuServe (GO MSLANG).

• Print and fax the order form accompanying the online version of this article on the Internet. Go to the Microsoft Home Page (http://www.microsoft.com), and choose the Developer Network OffRamp/Developer Network News. Or, on The Microsoft Network, open Categories/Computers & Software/Software/Microsoft/Microsoft Developer Network/News.


Globalizing Applications with MFC

F. Avery Bishop

May 9, 1995

Two features provided by the Visual C++ development system are designed to reduce a developer's time from concept to product ship: a class library that implements a large part of the Win32 API in C++ classes, and an integrated development environment (IDE) consisting of App Studio, AppWizard, and ClassWizard that practically writes your applications for you.

These tools can save time for developers writing internationalized applications as well.

Let's take a look first at what Microsoft Foundation Class Library (MFC) provides writers of international applications, and then go through an example of how to use MFC in such an application, employing ClassWizard.

Where did the NLS APIs go?

MFC is designed to implement Windows handles as classes. Thus, the device context (DC) class CDC corresponds to HDC, a handle to a device context. Similarly, CWnd corresponds to HWND, CWinApp to HINSTANCE, and so on. In general, those functions in the Win32 API associated with a handle became member functions of the corresponding MFC class. For example, you call SetMenu as a member of a CWnd object, LoadMenu as a member of a CMenu object, and LoadString as a member of a CString object (see below).

Those functions not logically associated with a class remain available as simple C-style functions. For example, you can still use the familiar NLS (National Language Support) API functions—such as GetLocaleInfo, SetThreadLocale, FindResourceEx, WideCharToMultiByte, and MultiByteToWideChar—as you always have.

On the other hand, the encapsulation of those functions that are directly related to an object helps application writers avoid such pitfalls as passing the wrong type of handle or otherwise misusing handles and other data types.

The CString class

MFC also provides utility classes not covered by the Win32 API. The CString class provides an assortment of member functions and overloaded operators for encapsulating textual data that helps speed the process of writing international applications. The CString class operators—such as + and += (concatenation), == (comparison), and so on—have the semantics of an actual string, rather than a pointer to a string, similar to string-handling conventions in Basic.

Where applicable, the member functions are locale or code-page sensitive. For example, the CString::Compare function uses the current locale setting to provide locale-sensitive comparison or sorting. As expected, the OemToAnsi and AnsiToOem member functions use the current OEM and ANSI code page settings to convert between the two.

The other convenient feature of CString objects is that the string buffer is based on the _TCHAR data type, so an application that makes full use of CString can be based on Unicode, single-byte character set (SBCS), or multibyte character set (MBCS). (See "Internationalizing with Visual C++" by Chris Weight in the September 1994 Developer Network News.)

Message handlers

ClassWizard uses message handlers to let you add processing for a specific Windows message or control without paging through a huge switch statement, as was necessary in straight ANSI C.

To implement a message handler using ClassWizard, you first select either the message that you want to process, such as WM_IME_NOTIFY, or a new command that you add yourself, such as ID_SELECTFONT. You also decide which of your application's modules should process it.

ClassWizard then inserts lines in a message map in your implementation of that module's class, indicating that the message or command is to be processed by a member function that you write, called a handler. It also puts a prototype of the handler in the appropriate header file, and gives you the option of editing a skeletal version of the handler in the source file for the module. A message handler is generally given a name of the form On<message name>—for example, OnImeNotify.

Japanese example

Let's look at some examples of how these various classes and member functions can be used together. Suppose you have an application that needs to change the language used in its user interface—that is, in its menu prompts, message text, and so on. One way to do that is to use the LANGUAGE keyword in the resource file. (This keyword is not directly supported by Visual C++ 2.0, but will be supported in a future version. See the "Resource Statements Not Supported by Visual C++" Help file in Books Online for an explanation of how to use this keyword using Visual C++2.0.)

For example, here is a Japanese menu.

The corresponding UK English menu is as follows:

#define LANG_ENGLISH 0x09

#define SUBLANG_ENGLISH_UK 0x02

//

// English menu

//

IDR_MAINFRAME MENU PRELOAD DISCARDABLE

LANGUAGE LANG_ENGLISH SUBLANG_ENGLISH_UK

BEGIN

POPUP "&File"

BEGIN

MENUITEM "&New\tCtrl+N", ID_FILE_NEW

MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN

MENUITEM "&Save...\tCtrl+S", ID_FILE_SAVE

MENUITEM "Save &As...", ID_FILE_SAVE_AS

/* etc. */

MENUITEM "E&xit", ID_APP_EXIT

END

POPUP "&Edit"

/* etc. */

POPUP "&Options"

BEGIN

MENUITEM "Change UI Language (&L)", ID_OPTIONS_LANGUAGE

END

/* etc. */

END

One can then select a locale and change the language used in menus and strings as follows:

void CMainFrame::OnOptionsMenuUI()

{

CMenu *pmnMenu ;

CString Error, Format, AppName ;

LCID dwSelected_LCID =

MAKELCID(MAKELANGID(LANG_ENGLISH,

SUBLANG_ENGLISH_UK), SORT_DEFAULT) ;

// Default locale.

// Omitted: Code to select locale, e.g., from

// a list box, and set dwSelected_LCID.

if(!SetThreadLocale(dwSelected_LCID))

{

VERIFY(Format.LoadString(ID_SETLOCALE_ERROR))

;

VERIFY(AppName.LoadString(ID_APPNAME)) ;

Error.Format(Format, dwSelected_LCID) ;

VERIFY(MessageBox(Error, AppName , MB_OK |

MB_ICONEXCLAMATION)) ;

return ;

}

VERIFY(SetMenu(NULL)) ; // Erases the

// current menu

pmnMenu = &mnLocalizedMenu ; // This is a

// global instance of CMenu

ASSERT(pmnMenu != 0) ; // Make sure the

// intialization

// worked

VERIFY(pmnMenu->LoadMenu(IDR_MAINFRAME)) ;

// Load menu of language ID matching

// current locale

VERIFY(SetMenu(pmnMenu)) ; // Set the menu

// in the main

// frame window

VERIFY(NULL!=pmnMenu->Detach()) ; // Local

// object will

// go out of

// scope

}

The VERIFY macro is a debugging device that does nothing in retail (nondebug) mode, but displays a warning message box and lets the user abort or ignore the error when the argument returns FALSE in debug mode. In the case of SetThreadLocale, an error message is displayed explicitly, because this error is likely to occur even in a "bug-free" retail version. To report the error, we have used the LoadString and Format (similar to sprintf) member functions of the CString object, and passed the formatted CString object to MessageBox, a member function of CWnd.

Note that SetThreadLocale is a simple Win32 function, rather than a member function of any class. SetMenu also appears to be a stand-alone function in this example, but it is actually a member function of the current object, CMainFrame (which is derived ultimately from the CWnd class). Thus, no class name is needed. In contrast, LoadMenu and Detach are member functions of the CMenu class, which must be explicitly indicated.

Text in a string table can also be marked with the Language keyword, enabling the language to be switched in the user interface. Any call to CString::LoadString will now load the string of the appropriate language, as defined by the current locale setting.

Anything Win32 can do...

Anything you can do in the Win32 API, you can do in MFC. Some of the Win32 NLS functions have been moved to member functions of classes, while others remain as stand-alone C-style functions.

The easiest way to find out where one of your favorite functions went is to highlight it in the Visual C++ 2.0 editor, and press F1. If the function is a member function of some class, the WinHelp application will give you a choice of the MFC version or the Win32 version of the help for that function. Otherwise, it will go straight to the Win32 description.

F. Avery Bishop, a technical evangelist in Microsoft's Developer Division, brews his own beer, speaks and reads Japanese, and will kill for good sushi.

An MFC Application's Basic Structure

The standard MFC-based application consists of four basic modules:

• CWinApp, the main module controlling the initialization and processing of the rest of an application. It corresponds roughly to a WinMain function in C-based Windows source code.

• A CMainFrame object and member functions, which make up the main window of your application.

• Single-document interface (SDI) and multiple-document interface (MDI) CDocument objects and member functions. These objects perform any direct processing of the data in the user's document.

• One CView object (or a derived class such as CEditView or CScrollView) for each CDocument object. This object is for display of the document and for receiving the user's input into the document.

The AppWizard in Visual C++ creates basic versions of these classes that an application writer edits and enhances.


Help Is On the Way

The new 32-bit Windows Help 4.0

Scott Henson

May 9, 1995

Excuse me. Have you been Helped?

No, we're not talking about trying on some new Birkenstocks or ordering a green salad with creamy vinaigrette. We're not talking about finding an efficient personal assistant. The kind of help we're dishing up can be found in the next wave of 32-bit Windows operating systems.

So how to get up and running with this new Help system? Hop into the Helpmobile and let's take a look.

First, let's talk about release plans for the new Windows Help version 4.0 engine and compiler. The WinHelp 4.0 engine (the 32-bit executable that displays the Help files) will ship with Windows 95 and Windows NT 3.51. The new WinHelp 4.0 compiler also bridges both platforms by allowing you to create your new WinHelp 4.0 content from either 32-bit operating system. Additionally, by the time Windows 95 is released to manufacturing, the new WinHelp engine will be released with version 1.3 of Win32s for use on Windows 3.1. By simply authoring one set of Help content, you're ready to ship full-featured Help for all three operating systems.

Let's also quickly talk about what you won't see. There will not be a WinHelp 4.0 compiler that runs on Windows 3.1, nor will WinHelp 4.0 files load on Windows NT 3.5. That said, let's start by looking at the plethora (I just love that word) of new features.

Help at first glance

At first glance you will notice a single entry point for Help: the Help Topics dialog box. This dialog box has tabs for contents, an index, and the hot new full-text search. The Contents tab displays the contents of the Help system in a familiar "table-of-contents" format. You can actually provide jumps to several Help files in a way that is transparent to users. If a user hasn't loaded a particular component of the program and its assigned Help file, WinHelp automatically drops all references to topics in that Help file so the user will never see those topics. This is great for updating Help files with maintenance releases, or if you have a knowledge base that continues to grow.

WinHelp also has a new Index tab similar in appearance to a book index, including second-level entries. The real power of the new index is the ability to combine the indexes from multiple Help files. In addition, index entries can invoke macros, which means there's no more need for dummy topics that only run an auto-entry macro.

Unless you add your own tab to the Help Topics dialog box, the last tab will be the Full-Text Search tab, which, for intermediate and advanced users, is one of the handiest features of WinHelp. It enables a user to search through every word in the Help file and look for matches. In addition to searching for words, WinHelp can search for phrases, and can find topics similar to ones the user has already found.

Beyond the interface

The initial interface is not the only aspect of WinHelp to go under the plastic surgeon's scalpel.

Take a look at the new copying capabilities. You can now select text from within the topic, copy and paste it into your e-mail, and send off the text.

WinHelp is now an OLE drag-and-drop source. You can drag and drop the selected text to any OLE drag-and-drop target (WordPad, for instance). Invite a few friends over for a barbecue, and there's your entertainment for the evening. If that weren't enough, from WinHelp you can now print multiple topics from the Contents tab. You can even print a pop-up topic by bringing up the context menu and selecting Print Topic.

Users now have the option of choosing system colors. One great use for this capability is to allow sight-impaired users to have the Help system go into high-contrast mode rather than overriding with its own color scheme.

Two new types of Help

WinHelp supports two new types of Help: context-sensitive and Training Cards. In addition to using the F1 key to access context-sensitive Help for an object or control in the Windows interface, a user can click the "?" button on the toolbar, and then click the object or control. The nice thing about context-sensitive Help is that the user gets immediate feedback about the item he or she clicked.

Training Cards, a set of Help topics in secondary windows, have been configured to send and receive instructions and information to and from other programs.

Developers can use the WinHelp API to run specific Training Cards, depending on which actions a user makes in a program. Similarly, the Training Card macro is used to inform the program of user actions within a Training Card, which the program can act upon in a specified manner. This capability is particularly useful in walking a user through an actual procedure, displaying a card with a new instruction whenever the user performs an instruction correctly, and displaying cards that respond to specific user mistakes.

Help for Help authors

What about the Help Author?

• You won't see those annoying "out of memory" messages when you compile. The new Help compiler is completely Windows-based and 32-bit, which gives you extended access to your system's memory.

• Secondary windows can now have button bars just like the main Help window, and you can add your own authorable buttons. These are real buttons, unlike their SHED graphic counterparts of the past.

• There is support for bitmaps with up to 16 million colors. If the current display color depth is lower than 16 million colors, WinHelp automatically reduces the color depth as necessary. You can also author bitmaps at multiple color depths, and let WinHelp determine the color depth capability of the monitor and use the appropriate bitmap.

• You can add animation and video files to topics by using the {mci} statement in the topic file. WinHelp plays back these files through the media control interface (MCI) in Windows. WinHelp supports motion-video files in Microsoft Video for Windows format.

• Two new linking macros, KLink and ALink, enable you to provide jumps to multiple topics based on keywords rather than specific context strings. The jumps are resolved at run time, so you can have jumps to other Help files that may or may not have been installed.

• There are several new compression schemes. Depending on the content of your files, you could see up to 10 percent compression of text and up to 90 percent for bitmaps (this depends entirely on the bitmap). For graphics-intensive Help files, the additional graphics compression could make a big difference.

New compiling and testing features

There are also new compiling and testing features:

• Windows-hosted tools for project and contents file editing, including a fast new compiler.

• The ability to launch your Help system in different ways, including calling it from another program, from the command line, or as a Training Card instance.

• A Help Author command allows you to see topic numbers in the title bar, provides easy keystroke access to step through the topic IDs numerically, and even adds additional commands on the context menu to get more information on topics and hot spots.

• A Report command allows the generation of a report on various aspects of a Help file. For each Help file, you can request reports by topic titles, hash numbers, and keywords. You can also request a report containing all the ASCII text in the Help file. This is great for a quick spell check of your Help files.

• Easier topic jumping. Just press CTRL+SHIFT+J from any topic window (except pop-up windows). This works with macros as well.

• The Test and Compare macros aid and help automate the thorough testing of your Help files.

More information

For more material on WinHelp, start by diving into the merged Win32 Software Development Kit on the Developer Network Development Platform. From the root directory, you will find the new Help compiler (HCW.EXE) and Help Author's Guide (HCW.HLP) in the WIN32SDK\MSTOOLS\BIN\I386 directory.

For those who would like a jump start into the WinHelp 4.0 Help authoring process, you can purchase (I promise it's only to cover costs) videotapes from the Windows Help Authoring Conference held in January in Redmond, Washington. To inquire about how to get these videos, e-mail helpvid@microsoft.com. You can also fax your request to (206) 936-7329, Attn: Windows Help Authoring Video Requests. If all else fails, you could send good old postal mail to:

Windows Help Authoring Video Requests
One Microsoft Way
Redmond, WA 98052

Scott Henson belongs to the Microsoft Developer Relations Group's Evangelical Choir. If he's not singing hymns of praise about Windows 95 or Windows NT, he's frolicking in the woods listening to Pearl Jam or Candlebox.


High-Performance Tuning for Win32

May 9, 1995

Your cool Win32-based application is up and running and you are pretty darn excited about the 32-bit world. But then doubt starts to creep into your mind and you say, "Hey, I know this app isn't performing to its potential. There must be some things I can do to make this faster."

So, how do you get the most bang for your bits? That's where this article comes in. Here are six easy tuning tips from Microsoft's performance gang.

#1. Do page tuning

The wstune utility is a valuable tool that runs on Windows NT and has been in the Win32 SDK since its earliest version. Using wstune to page tune your application on Windows NT can also help your application's boot time on Windows 95.

The program's working set is a collection of recently referenced pages in its virtual address space. As the working set size decreases, so does memory demand. Since it is advantageous to minimize the memory demand, the working set tuner's dynamic-link library (DLL) is developed to measure the code working set and to produce an ordering of the functions (procedures) within the code that will be small, if not minimal, in a paging environment.

#2. Prebase your DLLs

Make sure your DLLs are prebased contiguously in memory. This lets the system avoid the necessity of calculating an appropriate load address for the DLLs. You can look in your map files to see how big they are, and from that calculate their load addresses manually if you have to. Or you could write the appropriate makefiles to do this automatically.

If you are using the Microsoft Visual C++ tools, you can just run the Rebase applet that comes with it. Rebase automatically calculates the appropriate load addresses for your DLLs if you feed them to the applet.

#3. Properly prebind

Make sure your DLLs are properly prebound by using the "bind" utility that comes with your favorite compiler. This marks the import address table (IAT) as read-only, so the loader does not have to privatize a new page for the IAT for each LoadLibrary call.

The IAT provides the system with the specific addresses for all APIs called by a third-party DLL. These addresses are then used to jump to the appropriate API in the system code. The IAT is a minimum of one page (4K) of pagelocked data per client of the DLL.

For every n clients of a particular DLL, the loader would need to first create and then copy n private copies of the IAT for each client. This is a much more expensive operation than a simple page fault.

Note that you must prebind your DLLs against a set of specific target DLLs. The bind utility will automatically calculate the sizes of your DLLs versus the system DLLs. This technique allows you to optimize for only one platform. It probably makes most sense for developers to prebind against Windows 95 rather than Windows NT, because the latter is more likely to be running on a system with more RAM.

#4. Turn on page faulting in Windows 95

You can use page-fault tracing by installing the debug version of Windows 95 and then running SWITCH.BAT to install the retail GUI (graphical user interface). SWITCH.BAT is a batch file supplied with the Win32 SDK. It switches from debug to retail and back, depending upon the options you give. To turn on page-fault tracing, type ".mff" (without the quotation marks) into the wdeb386 kernel debugger. This will dump all faults to your debug terminal. An analysis of this data can tell you all sorts of things, such as how many page faults you're taking, as well as when you're faulting due to reading in code versus data.

It is important to finish one complete initialization before starting something else. In some cases an application calls the OleInitialize routines too early. This can cause thrashing when the application is started in low memory conditions because both the application and the OLE libraries are trying to finish initialization, but neither one can fully fit into memory simultaneously.

#5. Load later

To help application boot time specifically, try to delay loading certain components, such as MPR (network), SHELL.DLL, COMMDLG.DLL, printer drivers, the spooler, and so on, until they are actually needed. Delaying the loading of just one DLL doesn't help as much, but when you can do it for multiple DLLs on an 8-MG (megabyte) computer, your wins start increasing geometrically.

Are you doing small file reads? Sequences of 8-byte file reads at bootup can hinder performance. Do you do unnecessary disk writes at bootup? Look at any large allocations or files you create at boot time that could be moved to later on. Make sure you aren't loading any system DLLs you don't really need, such as the messaging API (MAPI) or the multimedia components

#6. Use Windows 95 call tracing

Use call tracing. Make sure you aren't passing in any bogus search paths for DLLs, or possibly looking for malformed DLLs. In some cases searching the path for DLLs is more expensive than explicitly changing directories to the application directory, loading the DLL, and then changing back to the working directory.

Often applications load six or seven of their own random DLLs, thus allocating and touching huge chunks of memory at bootup, and opening/closing temp files.

You can turn on call tracing in wdeb386 using this sequence of commands:

.c <return> 3 <return> 4 <return> y <return> n <return> ESC

Then watch what calls are made on your behalf down to the file system.

Tuning on Windows 95

Remember that it is especially important to tune your applications on Windows 95, because you may be running on computers with less memory than those running Windows NT.


Issues to Consider When Porting 16-bit Office Solutions to Windows 95

Ken Lassesen

May 9, 1995

Are you a solution provider or a corporate developer who has created a Microsoft Office-based solution? You may soon face an important challenge to ensure that your application runs successfully under Windows 95.

You may face the issue if your Office 4.x-based (or earlier) solution code (in Visual Basic for Applications, for example) calls the Windows 3.1 API or other 16-bit dynamic-link libraries (DLLs). If your application's users upgrade to Windows 95, and then upgrade their desktop applications to Office for Windows 95 (the 32-bit version of Microsoft's mainline desktop applications, due out this summer), some of your routines will fail, providing a "DLL could not be loaded" error message.

What is going on? Your Visual Basic for Applications, Access Basic, XLM, or WordBasic code is being run in a 32-bit application and is trying to call the Windows 3.1 API or other 16-bit process—unsuccessfully, because a 32-bit application cannot make a direct 16-bit API call. Conversely, a 16-bit application cannot make a direct 32-bit API call.

Calling a 16-bit process in a 32-bit world?

This may not be obvious. The current, 16-bit version of Microsoft Office and any solutions built on it will run just fine on Windows 95. In addition, the upcoming 32-bit version of Office 95 and any solutions built on it will run without difficulty on Windows 95. However, if you unwittingly mix a 16-bit solution with the 32-bit version of Office, you will find that your application does not work. Before users of your application begin switching to Office 95, you should plan to avoid this situation.

Two strategies for converting to 32-bit

Code written in any of the Office solution-building languages—including WordBasic, Visual Basic for Applications, and XLM in Microsoft Excel; Visual Basic for Applications in Microsoft Project; and Access Basic in Microsoft Access—must be updated when ported to Office 95 if the code calls the Windows 3.1 API or other 16-bit DLLs.

There are two ways to convert your 16-bit Office 4.x solution so that it runs correctly in 32-bit Office 95. Both options require that you do some new work.

Rewriting and recompiling

The first option is to rewrite and recompile any 16-bit DLL the solution uses to a 32-bit DLL and update the calling code, then update any Windows 3.1 call to its equivalent Win32 call, and after that redistribute the custom solution. This may mean all your users need to upgrade to 32-bit application engines concurrently, or use API wrappers as discussed below.

Most 32-bit Windows APIs have the same names as 16-bit APIs. The documentation in the Developer Network Development Library may show the same arguments with the only apparent difference being that the DLL's name changes from FOOBAR.DLL to FOOBAR32.DLL. This can mask significant differences:

• a change in data type size

• the addition of Unicode or ANSI options

• the addition of case sensitivity

For more information on this, the Visual Basic team is working on a Basic-oriented guide to the Windows 95 API. They hope to release it this summer.

Thunking

If you don't want to rewrite the 16-bit calls, then the other option is "thunking" (providing an interoperability layer between the 16-bit and 32-bit processes). This has other limitations. Thunking ensures that parameters are pushed correctly on the stack, and that memory addresses are converted from offset (32-bit) to segment::offset (16-bit).

Thunking requires changing both the 16-bit DLL and the 32-bit application solution code. If you can't change the 16-bit DLL for some reason, you must write a new 32-bit wrapper DLL. The 32-bit application (Microsoft Excel, for example) talks to this 32-bit wrapper DLL, which in turn talks to the real 16-bit DLL.

Although it is in some cases trivial to develop thunking functionality, it can involve creating pointers between the two layers, which is quite challenging and may lead to performance problems.

Note that there are different ways to thunk. For more information, check out "Diving into the Requirements for the Windows 95 Logo" by Denise Shephard in the Developer Network Development Library. This article gives an overview of thunking across the Windows platforms and contains pointers to more detailed information on thunking.

Additional issues

Simply converting your declare statements from Windows 3.1 API calls to Windows 95 calls may not be enough. There are other issues besides changing the name of the function's host DLL (such as from USER.DLL to USER32.DLL). For example:

• The required parameter data type may also have changed.

• The required parameters will need 32-bit values, not 16-bit values (requires padding).

• Windows 95 has made some Windows 3.1 API calls obsolete. For example, the way that Windows 95 handles such things as message passing has changed.

• Some APIs (for example, those that deal with .INI files) are now considered obsolete, and it is recommended that developers not use them.

Corporate applications?

These strategies take care of the problem if you are writing an application for yourself, since you know what your application engine operating system is.

However, if the application is to be distributed across a large organization with many users, you'll have to make it work on all the PCs, which may be running different versions of Windows and different versions of the application engines. Possibilities include everything from running 16-bit applications on a 32-bit operating system to running 32-bit applications on a 16-bit operating system (with the aid of Win32s).

Your code will have to determine what type of application your solution is using as its engine, without making an API call, so that you can make the appropriate call. The solution will be for you to put every API call into a wrapper—a Basic function or subroutine that checks the application and then issues the correct call. For example, in Microsoft Access:

Function Engine32bits%()

Engine32Bits=(SysCmd(7) > 2)

End Function

Declare Function GetProfileString Lib

"Kernel" Alias "GetProfileString16"(ByVal

lpApplicationName$, ByVal lpKeyName$, ByVal

lpDefault$, ByVal lpReturnedString$, ByVal

nSize As Integer) As Integer

Declare Function GetProfileStringA Lib

"Kernel32" Alias "GetProfileString32"(ByVal

lpApplicationName$, ByVal lpKeyName$, ByVal

lpDefault$, ByVal lpReturnedString$, ByVal

nSize As Long) As Long

Function GetProfileString(ByVal

lpApplicationName$, ByVal lpKeyName$, ByVal

lpDefault$, lpReturnedString$, ByVal

nSize%) as Integer

'We use 16-bit integer to appear like 16-bit call.

If Engine32Bits() Then

GetProfileString=GetProfileString32\

(lpApplicationName$, lpKeyName$,

lpDefault$, lpReturnedString$, nSize%)

Else

GetProfileString=GetProfileString16\

(lpApplicationName$, lpKeyName$,

lpDefault$, lpReturnedString$, nSize%)

End If

End Function

More information

Check out the July release of the Development Library for an expanded technical article, "Converting Your 16-bit Office Application to Run Under Windows 95," by the authors of this article. It will describe in greater detail how to deal successfully with the challenges involved in porting your code.

Ken Lassesen is a writer in the Developer Network Technology Group. He does his best coding when listening to Carmina Burana and snacking on lutefisk.

Michael Risse, a product manager for Microsoft Access, contributed to this article.

What Is an Application Engine?

A Microsoft Office product such as Microsoft Excel is called an application. The Microsoft Office family of products includes Microsoft Excel, Microsoft Word for Windows, Microsoft Access, Microsoft Mail, Microsoft Project, and Microsoft PowerPoint.

But developers also use the solutions languages in Microsoft Office products, such as Visual Basic for Applications in Microsoft Excel or Access Basic in Microsoft Access, to add custom functionality to these applications. The resulting solutions are also called applications. Oops, the term application has become fuzzy!

In the latter cases, Microsoft Excel and Microsoft Access are actually functioning as application engines that execute the code—macros, Visual Basic for Applications—that the Office developer has written. More specifically, application engines are the .EXEs that read the application code from another file and execute it.

A Microsoft Excel application (XLS) can be either 16-bit or 32-bit because it is not dependent on the application engine—except when it does API calls.

Traditional compiled applications are targeted for one operating system, which then defines the API calls. Applications executed by application engines, however, are not tied to the operating system; thus, the application may work or fail when making API calls, depending on the application engine used.


Microsoft Hatches 'Blackbird'

Tools for building new interactive multimedia apps

May 9, 1995

Microsoft has outlined new tools to support independent content providers (ICPs) for The Microsoft Network (MSN), Microsoft's planned online service, including a sophisticated design environment for online applications, code-named "Blackbird."

These tools will allow content providers to design, manage, and deliver a new generation of interactive multimedia applications and services. The tools include the Blackbird design environment, tools for creating, updating, and managing forums, and a software development kit (SDK) containing direct APIs to MSN services. The tools will be available to companies that have an established independent-content-provider relationship with MSN.

"With The Microsoft Network tools, we think ICPs will be able to create content never before seen in the online world, and they will be able to develop that content at reasonable production costs," said Russ Siegelman, general manager of the Online Services Group at Microsoft. "We feel development of a broad range of content and services will attract new online users and expand the online market."

Blackbird features a one-button publishing environment in which a user can automatically manage dynamic content, and a customizable viewer that takes full advantage of the capabilities of Windows 95. Content providers can use Blackbird to build online publications, consumer-oriented applications, business-to-business services, interactive advertising, electronic-commerce applications, and even interactive games for MSN.

Microsoft is also providing forum-management tools that allow content providers to control fully their online forums, update information, manage user access, handle transactions, and create forums such as bulletin boards, chat rooms, and file-download areas. These tools include a bulk upload tool and e-forms, and were first distributed in March at a conference of forum managers.

Microsoft will also make available additional development tools for MSN. The SDK provides access to chat, e-mail, and other APIs for MSN. With these APIs, developers can create their own client-server applications or use their own multimedia development tools for the MSN platform. A client-server version of the Microsoft MediaView multimedia development tool will also be available for MSN ICPs.


Microsoft Solutions Platform and Kit Available

May 9, 1995

Microsoft has introduced two products designed to make it faster and easier for developers to create custom, integrated client-server solutions. The Microsoft Solutions Platform and Microsoft Solutions Development Kit (MSDK) provide tools and information for solutions using components of Microsoft Office, Microsoft BackOffice, and Microsoft Visual Tool Suite.

The Solutions Platform includes Microsoft Office Professional version 4.3; Microsoft Project version 4.0; the Visual Basic programming system version 3.0; the Visual C++ development system version 2.0; the Visual FoxPro database management system version 3.0; Microsoft SQL Server, Workstation Edition version 4.21, and the MSDK (also available separately).

Details and information on pricing and ordering can be found in the Internet version of this newspaper. Go to http://www.microsoft.com and open Developer Network OffRamp/Developer Network News.


OLE Structured Storage

Charlie Kindel

May 9, 1995

A major feature of OLE is interoperability, the basis for integration between applications. This integration brings with it the need to have multiple applications write information to the same file on the underlying file system. This is exactly the same problem faced years ago when multiple applications began to share the same disk drive. The solution then was to create a file system to provide a level of indirection between an application "file" and the underlying disk sectors.

Thus, the solution for the integration problem today is another level of indirection: a file system within a file. Instead of requiring that a large, contiguous sequence of bytes on the disk be manipulated through a single file handle with a single seek pointer, OLE defines a model for treating a single file system entity as a structured collection of two types of objects—storages and streams—that act like directories and files, respectively. This model is called "OLE Structured Storage."

A model or an implementation?

OLE Structured Storage is both a model (a paper specification) and an implementation.

Microsoft has produced an implementation of the model that applications use on Windows, Windows 95, Windows NT, and the Macintosh. On other platforms, such as variants of UNIX, other vendors have provided or are planning to provide implementations native to those platforms. To facilitate this, Microsoft has made available to platform vendors a reference implementation of OLE Structured Storage in ANSI C form.

Storage and stream objects

The OLE Structured Storage model defines two types of storage elements: storage objects and stream objects. The operating or file system itself generally implements these objects; applications rarely, if ever, need to implement them. These objects, like all others in OLE, implement interfaces: IStream for stream objects, IStorage for storage objects.

A stream object is the conceptual equivalent of a single disk file. Streams are the basic file system component in which data lives; each stream has access rights and a single seek pointer. Through its IStream interface, a stream can be told to read, write, seek, and perform a few other operations on its underlying data. Streams are named by using a text string; they can contain any internal structure because they are simply a flat stream of bytes. In addition, the functions in the IStream interface map nearly one-to-one with standard file-handle-based functions such as those in the ANSI C/C++ run-time library.

A storage object is the conceptual equivalent of a directory. Each storage, like a directory, can contain any number of substorages (subdirectories) and any number of streams (files). Furthermore, each storage has its own access rights. The IStorage interface describes the capabilities of a storage object, such as enumerate elements (dir), move, copy, rename, create, and destroy. A storage object itself cannot store application-defined data except that it implicitly stores the names of the elements (storages and streams) contained within it.

Storage and stream objects are sharable between processes. This enables objects running in-process or out-of-process to have equal incremental access to their on-disk storage. Because OLE is loaded into each process separately, it must use some operating-system-supported shared memory mechanisms to communicate between processes about opened elements and their access modes. In that way, storage itself becomes another mechanism—an interface-based mechanism—for shared memory. In fact, OLE uses a shared stream implemented on top of shared memory to pass parameters and return values between proxy and stub objects when generating remote procedure calls.

Application design with structured storage

OLE Structured Storage makes it much easier to design applications that by their nature produce structured information. For example, consider a "diary" program that allows a user to make entries for any day of any month of any year. Entries are made in the form of an object that itself manages some information. Users wanting to write text into the diary would store a text object; if they wanted to save a scan of a newspaper clip they would use a bitmap object, and so forth.

Without a powerful means to structure information of this kind, the diary application might be forced to manage some hideous file structure with an overabundance of seek pointers.

In this kind of situation, even a small change in the size of a text object or an addition of a day or month might precipitate changes throughout the rest of the file to update seek offsets. Not only is this tedious to manage, but the application also would have to spend enormous amounts of time moving information around in the file to make space for data that expands. Or the application can move the newly enlarged data to the end of the file and patch a few seek offsets, but that introduces the whole problem of managing the free space created in the middle of the file to minimize waste as well as overall file size.

The problems are compounded further with objects capable of reading and writing their own information to storage. In the example here, the diary application would prefer to give each object in it—text, bitmap, drawing, table, and so on—its own piece of the file to write whatever the object wants. The only practical way to do this with a single, flat file is for the diary application to ask each object for a memory copy of what the object would like to store, and then the diary would write that information into a place in its own file. While this works reasonably well for small amounts of data, consider an object that wants to store a 10-MB bitmap scan of a true-color photograph—exchanging that much data through memory is horribly inefficient. Furthermore, if the user wants to later make changes to that bitmap, the diary would have to load the bitmap in its entirety from its file and pass it back to the object.

The OLE Structured Storage technology solves these problems through the extra level of indirection of a file system within a file. With OLE, the diary application can create a structured hierarchy where the root file itself has substorages for each year in the diary. Each year substorage has a substorage for each month, and so on. This is shown in the following illustration.

A structured storage scheme for a diary application. Every object that has some content is given its own storage or stream element for its own exclusive use.

This structure solves the problem of expanding information in one of the objects: The object itself expands the streams in its control, and the implementation of storage determines where to store all the information in the stream. The diary application doesn't have to lift a finger. Furthermore, the implementation automatically manages unused space in the entire file, again relieving the diary application of a great burden.

In this sort of storage scheme, the objects that manage the content in the diary always have direct incremental access to their piece of storage. That is, when the object needs to store its data, it writes it directly into the diary file without having to involve the diary application itself. The object can, if it wants to, write incremental changes to that storage, thus leading to much better performance.

If the user wants to make changes to that information later on, the object can then incrementally read as little information as necessary instead of requiring the diary to read all the information into memory first. Incremental access, a feature that has traditionally been very hard to implement in applications, is now the default mode of operation.

Direct access versus transacted access

Storage and stream elements support two fundamentally different modes of access: direct mode and transacted mode. Changes made while in direct mode are immediately and permanently made to the affected storage object. In transacted mode, changes are buffered so they can be saved ("committed") or reverted when modifications are complete.

If an outermost-level IStorage is used in transacted mode, a robust two-phase commit operation is used to publish those changes to the underlying file on the file system. That is, great pains are taken not to lose the user's data should an untimely crash occur.

Persistent objects

Because OLE allows an object to read and write itself to storage, there must be a way through which the client tells objects to do so. The way is, of course, additional interfaces that form a storage contract between the client and objects. When a client wants to tell an object to deal with storage, it queries the object for one of three interfaces, as suits the context:

• IPersistStorage: Object can read and write its persistent state to a storage object. The client provides the object with an IStorage pointer through this interface. This is the only IPersist* interface that includes semantics for incremental access.

• IPersistStream/IPersistStreamInit: Object can read and write its persistent state to a stream object. The client provides the object with an IStream pointer through this interface.

• IPersistFile: Object can read and write its persistent state to a file on the underlying system directly. This interface does not involve IStorage or IStream unless the underlying file is itself accessed through these interfaces, but the IPersistFile itself has no semantics relating to such structures. The client simply provides the object with a filename and orders to save or load; the object does whatever is necessary to fulfill the request.

Conclusion

OLE Structured Storage enables many significant user features, such as property browsing, content indexing, and document sharing. The Windows 95 shell, for example, can display document summary information properties (author, word count, and so on) for any structured storage file. This feature alone makes structured storage worth using in your applications. The next version of Windows NT, known as Cairo, will take structured storage a step further by providing a native file system implementation and will support content indexing across the enterprise.

For a more in-depth discussion of OLE Structured Storage, read section 2.5, "Persistent Storage," of "The Component Object Model Specification" (March 6, 1995 draft), which can be found at ftp.microsoft.com in the /developr/drg/OLE-Info/COMSpecification directory. This specification is also available in the Development Library under Specifications, Common Object Model (COM) Specification.

Charlie Kindel is a program manager in the Windows NT/Cairo product group working on OLE. He's a too-proud father of nearly two-year-old Christine, loves collecting guns, and really wants a 1967 Porsche 911.

MFC Support for OLE Structured Storage

The Microsoft Foundation Class Library (MFC), starting with version 2.5, makes it easier to implement OLE Structured Storage in your applications. With a single call to EnableCompoundFile, a COleDocument derived class will automatically use structured storage when serializing its data. Developers using COleDocument don't have to deal with IStorage and IStream pointers directly; the default implementation automatically handles everything for you. The same is true for the other MFC OLE classes that derive from COleDocument (COleLinkingDoc and COleServerDoc).

COleStreamFile derives from the MFC CFile class and allows you to treat stream access as though you were actually accessing a file. You can associate an existing stream with COleStreamFile through the constructor or the ::Attach method, open or create a stream on a specific storage through the ::OpenStream or ::CreateStream method, and create a memory-based stream by calling the ::CreateMemoryStream method.


Sales-System Designers Sold on Visual C++

Linda Richmond

May 9, 1995

Solution sought: How can a large organization track sales opportunities, all the way from first contact to final product delivery—especially a vendor who deals in a variety of distribution channels, languages, and currencies?

Solution offered: The Siebel Sales Information System, created with the Microsoft Visual C++ development system by Siebel Systems, a young client-server software firm in Menlo Park, California.

"The time it takes to get a software product to market is simply everything," said president and CEO Thomas M. Siebel. "Our use of new Microsoft development tools enabled us to bring our product to market one full year earlier than we would have using any other development environment."

Many potential users of the Siebel Sales Information System distribute through such diverse channels as field sales, telemarketing, or third-party distribution. Besides online sales and product information, the product had to support multiple languages and currencies concurrently.

The system employs Microsoft Excel, Microsoft Word, and Microsoft Mail, plus Microsoft BackOffice networking and systems management software, and works under Windows version 3.1, Windows 95, Windows for Workgroups, and Windows NT operating systems and in conjunction with Microsoft SQL Server.

Why Visual C++ was chosen

Siebel Systems chose Visual C++ as the design environment largely because of the Microsoft Foundation Class Library (MFC) and the strength of its support for the Windows API and OLE.

MFC is designed to be compatible with the naming conventions used for the Windows API. This means that the MFC calls are very similar to the Windows API calls, so the learning curve is relatively slight. Also, developers can mix Windows API code with MFC.

Because using MFC results in a smaller code body with fast execution speeds and small executables, developers find that it allows them to write, test, and debug far less code. "We want to be first in the marketplace with the best possible product," said Bill Edwards, Siebel's vice president of engineering. "The fact that we're already in Windows makes us extremely cutting edge. Visual C++ with its MFC and OLE support helped us get there."

Another benefit Siebel's development team saw is the multithreaded preemptive multitasking support provided by Visual C++ with MFC, allowing more connections by users.

Edwards said his group also admired the Visual C++ integrated development environment (IDE) that allows them to build, edit, browse, and debug in the same development environment.

"The IDE and Project Manager remove a lot of the frustrations a developer typically went through in the past," explained Edwards. "One real help for us was the ClassWizard feature, which allows us to view and edit a class easily, while preserving any manual changes that were made. This is a big advantage over typical 4GL tools."

The 10-person Siebel development team particularly liked the new, faster incremental linker, which speeds up development time—especially with large applications—by relinking only the edited code.

OLE support enhances product's features

"Each Siebel client has different needs," said Pat House, vice president of marketing, "so our product has to be versatile enough to meet those needs.

"The OLE support offered by Visual C++ gives us a very configurable and flexible product to take to our customers. We're getting a great response to the Siebel Sales Information System because of its inherent flexibility, thanks to Visual C++. The sales user can work in our application, yet seamlessly access other integrated productivity tools."

OLE support and automation enabled Siebel to enhance its new product by incorporating other Microsoft products, such as Microsoft Excel and Word, into one package. OLE saved Siebel from having to write new code for de facto market standards to provide word processing, spreadsheet, report writer, and online documentation accessing capabilities.

Because OLE support broadens an application's feature menu, Siebel easily incorporated these features into its application. And through OLE, applications interact in a more efficient way. MFC provides support for OLE technology, making object linking and embedding easy to implement. MFC consolidates lower-level OLE programming into higher-level C++ class APIs.

An easy jaunt to 32 bits

Siebel developed its Sales Information System as a 16-bit application, but also designed it for 32-bit Windows 95 interface standards with OLE capabilities.

Through MFC, Siebel preserved the code for use with future technology enhancements. By using MFC-based code, Siebel's development team was able to port its product quickly to Windows NT as a native 32-bit application simply by recompiling it. The application immediately ran on Windows 95. Siebel credits the preemptive multitasking ability of Windows NT with fostering a 10 to 50 percent performance improvement in the product, depending on the task.

For more information

For more information about Microsoft products, call Microsoft Sales Information Center at (800) 426-9400. In Canada, call the Microsoft Canada Customer Support Centre at (800) 563-9048. Outside the United States and Canada, please contact your local Microsoft subsidiary. For information about the Siebel Sales Information System, contact Siebel Systems at (415) 329-6500.

Linda Richmond, a marketing communications consultant in Microsoft's Visual C++ product management group, devotes her spare time to annoying nontechnical friends with Visual C++ trivia.


Target: The Microsoft Network

Developer Network does double duty online

Handan Selamoglu

May 9, 1995

It was a perfect match. The first time we saw The Microsoft Network (MSN), the new online service included with Windows 95, we knew it offered an excellent opportunity to expand and complement our existing CD-ROM and printed publications from the Developer Network.

MSN is sleek. It is elegant. It is nimble. One click from the Windows 95 shell gives you immediate access to a whole set of services—chat areas, bulletin boards, worldwide e-mail exchange, and, most importantly, a rich online-publishing environment—the perfect place, we thought, to communicate with developers and to publish up-to-date technical information. The Developer Network thus became one of the first content providers on MSN—the proud owner of the new Developer Network forum.

To access our new area on MSN, click the Microsoft Developer Network icon located in Categories/Computers & Software/Software/Microsoft. Double-click the icons in the window to open the titles and services listed.

Building on past online experience

As most of you know, this is not our first foray into the online arena. In addition to our dedicated CompuServe forum (GO MSDN) and share on the Microsoft ftp server (ftp://ftp.microsoft.com/developr/msdn), we recently launched the Developer Network OffRamp on the World Wide Web (http://www.microsoft.com, and click on Developer Network OffRamp). Now the Developer Network forum on MSN gives us the opportunity to expand our online presence and to deliver information and news to a larger number of developers.

Over the last few months, we've started working with other groups at Microsoft to populate the Developer Network forum with useful information and services for our members and for other developers. We've defined seven major sections, which provide the information listed below. (These sections are currently in the prototype stage and contain only a few articles.)

News. An online version of Microsoft Developer Network News. However, this section provides much more than a sampling of news, features, and columns from the printed version of the newspaper. Posting on MSN allows us to bypass the space and scheduling restrictions of print-based media, and gives us the opportunity to post updates, news, and event notifications on a weekly, daily, even hourly basis.

Products. Data sheets, specifications, demos, and related information on Microsoft development products.

Solutions. In-depth technical information and selected case studies that demonstrate how to build solutions with Microsoft tools and technologies.

Technology & Strategy. Strategic overview of Microsoft client-server and database technologies for enterprise-wide application development.

Resources. Overview of online services, publications, and other resources available to developers who write applications for the Windows and Windows NT operating systems.

Library Sampler. Selections from the current issue of the Development Library.

Platform Overview. Introduction to the Development Platform CD-ROM, and a complete listing of operating systems, SDKs, and toolkits on the latest version of the Platform.

In the Library Sampler area, we post selections from the Development Library along with new articles and updates. Click a title from the left pane to view an article. Click the button(s) in the article to download sample code from a bulletin board.

You can also use the Chat and Member-to-Member BBS sections to share information with other developers, Developer Kiosk to see an introduction to the Developer Network forum, and Feedback to send us your comments and suggestions.

First the hors d'oeuvres, later the entrée

Please consider this first attempt a prototype, and pardon the meager diet currently posted. We will be fleshing out and refining the Developer Network forum in the coming months.

Before we take the next step, though, we need your help: If you have a copy of the Windows 95 pre-release, please take a look at the Developer Network forum and tell us what you think. Are we on the right track? Are we giving you the information you need?

Also, if you're interested in creating content for MSN, you may be pleased to learn that a new online publishing environment is currently in the works (see "Microsoft Hatches 'Blackbird'").

Handan Selamoglu has become the fastest RTF converter in the West. In her spare time she enjoys raising pandas in her backyard.


Windows 95: You Got It!

Getting prepared for the 32-bit application development trip

Tammy Steele

May 9, 1995

The pre-release version of Windows 95 has now shipped to Level 2 members of the Developer Network.

It comes with the merged Win32 Software Development Kit (SDK) for developing applications for Windows 95 and Windows NT. The pre-release Win32 SDK upgrades the current Win32 SDK, allowing developers to write to a single API and target multiple software and hardware platforms. Developers writing to the Win32 API can target Windows NT, Win32s, and Windows 95, as well as the Apple Macintosh platform (with the Microsoft Visual C++ 2.0 Cross-Development Edition for Macintosh).

The Windows 95 itinerary

So, your bags are packed and you're ready to go. Because you've been reading about your trip for so long, maybe it would be a good idea to review the travel plans.

First stop is beautiful downtown Win32. Next you'll visit the lovely OLE mass-transit system, with a brief encounter in Long Filename support and a stop at the Universal Naming Conventions studio tour. From there you'll move on to Simple Messaging API (MAPI) and finish with a spot of refreshment at the Windows NT 3.51 Toolbar and Grill.

As for guide books, let's start with the panoramic overview of your trip down Windows 95 Development Row (or would that be Chicago Memory Lane?), courtesy of back issues of Developer Network News, available in the Developer Network Development Library:

• "Windows 95 controls on Windows NT" by Tammy Steele, March/April 1995 (this article is also available in this online edition of the newspaper under "Features").

• "Getting your app ready for Chicago" by Robert Hess, September 1994

• "How to adapt an app for Chicago" by Tammy Steele, July 1994

• "Next stop: Chicago" by Tammy Steele, March 1994

• "Just what is an 'OLE application'?" by Kraig Brockschmidt, March 1994

(Although it's not available on the Library CD, members who've kept hard copies of back issues can also read "The Win32 story" by Tammy Steele, September 1993.)

Go to the library

These articles lay the groundwork for the development trip. Next, let's get out the binoculars and take a closer look at some of the technical article landmarks, also courtesy of the Developer Network Development Library:

• "Diving into the Requirements for the Windows 95 Logo" by Denise Shephard (A must read! Five stars for this one!)

• Nancy Winnick Cluts' series on Win32 common controls

• "Win32 Application Support for Plug and Play" by Lee Fisher

• "Generic: Anatomy of a Simple Win32 Application" by Robert Hess

• "Configuration Management and the Registry" by Kyle Marsh

• "Creating a Windows 95 Explorer-like Application" by Nancy Winnick Cluts

• "Using the Common Dialogs Under Windows 95" by Nancy Winnick Cluts

• "Developing Applications with OLE 2.0" by Kraig Brockschmidt

But wait! There's more! In the Microsoft Systems Journal section of the Development Library, you'll find 19—count 'em—articles on Windows 95. The Development Library also contains dozens of additional technical articles and newspaper articles to help you with your development. Simply search on "Windows 95" or "Chicago" and you'll be ready.

You'll take home more than memories from this trip. You'll have a great Win32-based application that exploits the capabilities of Windows 95 and Windows NT 3.51, and a Windows 95 logo to boot.

Buen viaje!

By day, Tammy Steele is a technical evangelist in the Developer Relations Group, focusing on Windows 95. At night, she becomes "Pammy Speel," Microsoft spokesperson and cabaret singer/travel guide.


Ask Dr. GUI #21

(Remember, he's not a real doctor.)

Created: October 21, 1994

Have a question? Dr. GUI's busy operating schedule won't allow him to answer all questions, but the Good Doctor will answer as many as he can in the next release of the Microsoft Development Library. Send your questions to:

Dr. GUI
Microsoft Developer Network
One Microsoft Way
Redmond, WA 98052-6399

Fax: (206) 936-7329, Attn: Developer Network
Internet: msdn@microsoft.com

The Doctor's Bag

Every good doctor has a black bag, at least in movies from the 1950s. I too have a black bag. It is a mail folder labeled "Dr. GUI." As I watch messages in various e-mail groups, I take those items that seem interesting. The problem, though, is that I seldom get to use this information to solve your problems. So I thought that I would devote Dr. GUI #21 to technical questions and answers propagated within the hallowed walls of Microsoft.

Questions in this issue:

WinMain Unresolved External

ODL File Ignored

Menu Resource ID and Buttons

Remove Title Bar and Menu

Disappearing Toolbar

Adding and Removing Property Pages


 WinMain Unresolved External

Dear Dr. GUI:

I'm building a Visual C++ 2.0 OLE application with Unicode support. As soon as I add UNICODE and _UNICODE as global settings (for CRT and Win32 libraries) to my AppWizard output, the linker returns a "WinMain unresolved external" error message. Yes, I have read about the WinMain LPSTR parameter, and I have installed the Unicode MFC [Microsoft Foundation Class Library] libraries, but I am still unable to link my Unicode MFC application.

Dr. GUI replies:

Your linker project settings need to specify an entry-point symbol. Use wWinMainCRTStartup as the symbol. You can do this by selecting the Link tab in the Project Settings dialog box. Then, in the Category list box, select Output. You can now specify the entry-point symbol as indicated above.


 ODL File Ignored

Dear Dr. GUI:

For some reason ClassWizard refuses to put anything in my .ODL file. After I created the project I added seven or so methods and properties, and they are in my .ODL file. However, when I try to add any new methods or properties, the .ODL file is ignored and the "Dispatch and event IDs" section in my include file is empty:

// Dispatch and event IDs
public:
   enum {
   //{{AFX_DISP_ID(CTickCtrl)
   //}}AFX_DISP_ID

It looks as if somehow ClassWizard "forgot" that I wanted a typelib. What can I do to make it "remember" again?

Dr. GUI replies:

Here's what you can do.

1. Manually add the appropriate DISP_IDs for methods and properties after the enum keyword.

2. Exit Visual C++ 2.0 and delete the .CLW file.

3. Start Visual C++ 2.0 again, and regenerate the .CLW file by opening the .RC file and pressing ctrl+w.

4. Exit Visual C++ 2.0 again, and open the .CLW file in Notepad. Add the following line to the [General Info] section:

ODLFile=foo.odl

5. Load the project, and it works!


 Menu Resource ID and Buttons

Dear Dr. GUI:

Somewhere I read or was told that if you want a dialog box button (for example, Exit) to do the same thing as a menu item (File Exit), just give the button the same resource ID as the menu item (ID_APP_EXIT). Then the Microsoft Foundation Class Library (MFC) message machinery will cause the menu item command handler to get called magically when the button is clicked. I tried this long ago and gave up when it just didn't work. I tried it again today and it still doesn't work. Now I'd like to know why.

Dr. GUI replies:

I just tried it. It worked. For fun, add a button to a default AppWizard application's About box. Use ID_APP_EXIT as the ID for the button. Run the application, choose the About dialog box, click the button, and the application exits.

This works so well in App Studio 1.0 that, if you place a button on your own dialog box in the dialog editor, go into test mode, and click the newly created ID_APP_EXIT button, App Studio will exit!

One thing that may be causing your problems: This is designed to work only for IDs with the high bit set.


 Remove Title Bar and Menu

Dear Dr. GUI:

Please forgive my ignorance. I'm learning MFC as quickly as I can, but my boss wants the application written with MFC. However, it will not look like your standard MFC single-document interface (SDI) ClassWizard-generated application. No menu or toolbar, and the title bar and system menu will most likely be faked rather than use the standard Windows title bar and so on. Well, the wizard let me turn off practically everything, except the title bar and menu.

So I edit the RC file and remove all menu items from the main menu, which, as far as I can tell, removes the menu itself. The application still compiles and builds but won't run. Running it through debug, it stated the following:

MFC30D.DLL Initializing!

Warning: Failed to load menu for CFrameWnd.

Warning: CDocTemplate couldn't create a frame.

Warning: m_pMainWnd is NULL in CWinApp::Run—quitting application.

MFC30D.DLL Terminating!

Process 0xBD terminated, exit code 0 (0x0).

From the documentation, it appears that I can have a NULL menu and CFrameWnd would accept that. But apparently that isn't the case. Do I have to have a menu with an SDI MFC application? Or, for that matter, a title bar?

Dr. GUI replies:

Response 1: You will need to override CFrameWnd::LoadMenu if you intend to use the Microsoft Foundation Class Library (MFC) document/view architecture (which is what AppWizard provides). You will also need to override CFrameWnd::PreCreateWindow so you can tweak your window style so that a caption is not on the main window.

Response 2: You might be better served by implementing your application as a dialog-based application. Unless you need the document/view architecture (which I doubt from the sound of it), I believe this is the way to go.


 Disappearing Toolbar

Dear Dr. GUI:

I have a CToolBar object in a CWnd derived class. During the CWnd derived class's OnCreate member, I call the CToolBar's Create member (I used code similar to that in the MAINFRM.CPP file of an AppWizard-generated application). It looks like this:

// create button bar
if (!m_buttonBar.Create(this, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS)
    ||!m_buttonBar.LoadBitmap(IDB_BUTT_BAR)
    ||!m_buttonBar.SetButtons(bButtons, sizeof(bButtons) / sizeof(UINT)))
{
  TRACE0("Failed to create Button Bar\n");
  return -1;      // fail to create
}

The m_buttonBar object is a CToolBar object declared in the CWnd class header. I do not want the toolbar to be "dockable" or "floatable," so I removed the CBRS_FLYBY flag and do not call EnableDocking. The code appears to execute OK (there are no assertions), but the toolbar never appears!

Dr. GUI replies:

You should probably set the size of the toolbar. By default the width and height are (0, 0) since the CFrameWnd class controls its size (see CWnd::MoveWindow).


 Adding and Removing Property Pages

Dear Dr. GUI:

I am writing an application that uses property sheets. One of the property pages in the sheet has a set of radio buttons that control the total number of property pages displayed. Basically, these radio buttons allow users to dynamically remove and add property pages to the property sheet.

So far, I am able to dynamically remove the property page, but adding it dynamically is a little slow. It waits until I change to another property page before I see the newly added page. I would like for it to happen immediately, like after I click to select the radio button to add. Is there any way I can flush to request to add the page as soon as possible? Any hacks?

Dr. GUI replies:

This is a bug. The tab control is not being invalidated when an item is added. You can easily work around this, though. After calling AddPage, invalidate the tab control:

m_pSendPS->GetDlgItem(AFX_IDC_TAB_CONTROL)->Invalidate();

This will be fixed for a future release, so you might want to include this line in your code:

#if (_MFC_VER <= 0x300)... #endif.


COM: A Model Problem Solver

Binary standard lays foundation for component software

Paul Stafford
Joel Powell

March 10, 1995

Are you curious about what the Component Object Model (COM) is and what it can do for your applications? Knowing what types of problems you can address and solve using COM is a key part of deciding if it is for you. Before discussing that, a brief look at the basics is in order.

COM is a component software architecture that allows binary components supplied by different software vendors to interoperate in a reliable, controlled manner. In the past, independent software vendors (ISVs) developed applications that operated in their own world; those applications were their own world. The products that emerged resulted in little or no interaction among applications. Even when ISVs made a sincere effort to get their programs to interact, there was no clear standard and, as a result, getting different applications to interact was difficult at best.

Now, the programming mind-set is changing. Terms such as "document-centric" and "component software" are taking hold. The shift has opened a new world—and challenge—to today's programmers. COM helps jump-start this process by defining a binary standard that extends component capabilities at the system level.

But why should developers care about COM?

Put simply, COM lays the groundwork on which we can build component software.

COM represents a binary interface standard that allows developers to build specialized software components that interface in a common way with other software components. OLE is built on the foundation that COM provides.

Software vendors don't need to communicate with each other to exchange specifications or in any way coordinate the design and assembly of their specialized software components. They just need to build components that adhere to the OLE interface standards.

The idea is to enable the software industry to achieve greater rates of innovation, more specialized customer solutions, higher quality applications, and a faster, less expensive development process. (See "The benefits of component software" by Gregory Leake, Developer Network News, November 1994.)

Four problems that COM solves

Here are four basic problems that arise in a component-based system. We'll discuss how COM solves these problems:

• Interoperability: How can components supplied by different software vendors interoperate safely?

• Versioning: How can one system component be updated without replacing the other components in the system? How does COM let you provide new versions of components while maintaining reliable backward compatibility?

• Language independence: How can function calls be made between components written in different programming languages?

• Transparent remoting: How can clients communicate with component objects without being concerned whether those components are running in the same process, in a different process, or even on another computer?

Basic COM terminology

Before we look at how COM solves these problems, let's define some essential terms.

V-table

When you have a pointer to a COM component, you actually have a pointer to a pointer to a virtual function table, or v-table. This v-table contains pointers to the functions within the component (Figure 1):

-

Figure 1. Representation of a v-table in a component object

Interface

An interface is a group of semantically related functions, or "methods." Taken together, the methods in an interface define a logical group of services that a component object can provide to the system.

The definition of an interface forms a contract between COM components and component users. This contract is a definition of expected behavior and responsibilities. Interfaces are immutable—methods cannot be added to or removed from an interface. Once defined, the syntax and semantics of interface methods can never change.

An interface itself has no implementation; therefore, it cannot be instantiated. It is the programmer's responsibility to provide an implementation for the interface. Different COM components may implement the same interface differently; however, the contract states that the behavior must be the same.

Microsoft already defines many standard interfaces. For example, there are general interfaces (such as IDataObject and IDropTarget), OLE interfaces (such as IOleObject and IOleContainer), and many others supporting OLE Automation and OLE Controls. If you cannot find an interface that defines the services your component wants to provide, you can create your own custom interface.

Interfaces are strongly typed; each interface has its own unique interface ID, or IID. An IID is actually a globally unique identifier (GUID). A GUID is a unique 128-bit value that allows COM to properly identify a specific interface. You can generate your own GUIDs with GUIDGEN, a tool provided with Microsoft Visual C++ 2.0.

COM components and the component object library

Basically, a COM component consists of compiled code that provides services to the system. It differs from a C++ object in that its data is always private; the only way to access a COM component's data is through one of its interfaces.

In C++ you instantiate an object by using the new operator, which returns a pointer to the C++ object's v-table. With COM, you must communicate with the Component Object Library to obtain an initial interface pointer on a component. This library is provided as part of the operating system—to date on Windows, Windows NT, Windows 95, and the Macintosh—and contains the basic "plumbing" that enables components to find, connect to, and communicate with other components in the system.

All COM component interfaces must derive from a base interface named IUnknown. IUnknown has three methods: QueryInterface, AddRef, and Release. QueryInterface lets a client obtain a pointer to another interface supported by the component (if it exists). AddRef and Release are counting methods that allow a component to control its own lifetime.

COM components are housed in either a dynamic-link library (DLL) or an EXE; this housing is the component server. DLL component servers are labeled in-process servers or in-proc servers. EXE component servers are labeled local servers if the component is running in a different process but on the same computer. EXE component servers are labeled remote servers if they are running on a different computer.

COM components are often referred to as "Windows objects," "component objects," or "components." All these terms mean the same thing. Using such terms separates them from C++ objects, which, hopefully, reduces confusion between the two. We'll use the term "client" to refer to any piece of code that calls a component's interface methods.

Armed with these terms and a brief definition of a COM component, let's look at the solutions COM provides for the four problems we outlined earlier.

Solving the problem of interoperability: The binary standard

A client obtains the services of a COM component by calling interface methods provided by the component. When one component makes a call to another, an important question arises: How can such a call be made safely when the other component may have been written at a different time, by developers in a different software company, and in a different programming language?

COM enables calls to be made between components by specifying a binary standard for such calls. The standard specifies how a component constructs the v-tables for its interfaces, and how the client calls interface functions indirectly, through the v-tables. COM's binary standard allows clients to safely call a component's interface methods, without concern for the component's implementation language.

Interface "contracts"

Once the client is successfully making calls to the component server, it needs to know exactly what services it will receive. COM interfaces specify the semantics of interactions between components.

The specification of a COM interface serves as a contract between the client calling the interface's methods and the component providing an implementation of the interface. This contract specifies the services that the client can expect to receive from that component. The contract is good for all time, because COM interfaces are immutable. Once an interface is defined, the semantics and syntax of its methods can never change.

Encapsulation

For a component object system to be robust, components must always be able to protect themselves from direct access by other components. The use of interfaces allows COM to ensure complete encapsulation of a component's internal data and processing.

Clients never have direct access to a component's internals. Instead, clients have interface pointers on the component, and obtain all services by calling interface methods indirectly through that pointer. The interface pointer is opaque; all implementation details and internal data are hidden from the caller.

The Component Object Library

The Component Object Model is a specification, but it also has an implementation—the Component Object Library.

A client wanting to use the services provided by some particular component object class starts by calling the Component Object Library, asking for an interface pointer on a component of that class. The Component Object Library then does the "legwork" necessary to hook up the client and component. First it finds and runs the server executable (DLL or EXE) associated with the component class and asks the server to create an instance of the component. It then obtains an interface pointer on the component, and finally returns that pointer to the client.

The client can now make calls to the component through the interface pointer. It can also obtain additional services from the component by obtaining additional interface pointers (via IUnknown::QueryInterface).

Versioning and backward compatibility

COM provides a versioning mechanism that allows seamless evolution of components. When one system component is updated, it is not necessary to replace the other components in the system. Existing clients of the component do not need to be recompiled, rebuilt, or even notified. The new version of a component can easily maintain backward compatibility with old clients, while at the same time adding new features to be used by new clients.

The first key to versioning in COM is that interfaces are immutable. Because it is not possible to add new functionality to an old interface, the only way that a component can add new features is to expose those features via a new interface. This interface is not a new version of the old interface—interfaces are never versioned. Instead, it is a completely new interface, with its own unique IID.

The second key is IUnknown::QueryInterface. This call allows clients to determine the capabilities of a component at run time. Clients that want to use the new features will simply use QueryInterface for the new interface.

Maintaining backward compatibility with old clients is simple—just continue to support the old interface. Because interfaces are immutable, existing client code is not broken.

Note that as long as the syntax and semantics of the interface methods are preserved, the methods can be reimplemented internally—for example, to improve performance. Existing clients will call the methods just as they always have, and benefit from the increased performance "for free."

language independence

COM is language independent. By specifying a binary object standard (as opposed to a source code standard, such as C++), COM enables calls to be made between components written in different programming languages (C, C++, Small Talk, and so on).

Components can be implemented in any language that supports the creation of v-tables. They can be called from any language that supports indirect calls through function pointers. Typically, the various components in the system have been written in many different languages.

Transparent cross-process interoperability

As described earlier, COM component servers can be implemented in three flavors: in-process, local, and remote. Fortunately, clients do not need to know (or care) which kind of server they are calling. COM provides "transparent cross-process interoperability." This means that clients use the same simple programming model when calling any component. The Component Object Library insulates the client from the specifics of where the component is actually running.

The three possible scenarios are shown in Figure 2. Calls to in-proc components are simply direct calls to the component. Overhead is minimal, allowing in-proc components to provide the best performance.

Figure 2. In-process, local, and remote server interoperability

Local components cannot be called directly, because they are running in a different process space than the client. Calls to local components are intercepted by a "proxy" object provided by the Component Object Library. The proxy generates a call through the LRPC (lightweight remote procedure call) channel to a "stub" object (also provided by the Component Object Library) that runs in the process space of the local component. The stub object then completes the procedure by making an in-proc call to the local component.

The key point is that any differences between the in-process and cross-process cases are transparent to both clients and components. Clients always make calls through an in-process pointer, and components are always called via some in-process pointer. Any extra work needed when making calls across process boundaries is handled "magically" by the Component Object Library.

In 1996, Microsoft plans to release a version of the Component Object Library that will extend transparent remoting to include calls between two machines on a network. Existing components will not need to be rebuilt then; components that can make cross-process calls today will gain the ability to make cross-network calls "for free."

Getting started

A host of information is at your disposal. To name just a few sources: Inside OLE 2 by Kraig Brockschmidt (available in the Developer Network Development Library) and the OLE Programmer's Reference Volume 1 and Volume 2 provide a good head start; they are all available from Microsoft Press. Also, check out the full COM specification provided in both the Development Library and with the Visual C++ 2.0 CD. If you have any problems, concerns, or ideas, feel free to contact Microsoft on CompuServe (GO WINOBJ).

Joel Powell is a support engineer specializing in COM and OLE. He is also a published author of books ranging from Win32 programming to computer gaming.

Paul Stafford is an engineer in the Windows Developer Support Group, specializing in all things OLE. Joel's books occupy the place of honor on Paul's bookshelf, right next to the OLE Programmer's Reference.


Deep C++: Converting Large Dialogs into Property Sheets

Nancy Winnick Cluts

March 10, 1995

When your dialog boxes are displayed, do people run screaming from the room? Are your dialog boxes so large and confusing that they produce pounding tension headaches?

Maybe you should think about converting those Byzantine boxes into property sheets (or tabbed dialog boxes, as they are also commonly known). This article takes you through the process of converting a large dialog box into a property sheet using the built-in CPropertyPage and CPropertySheet classes of Microsoft Foundation Class Library (MFC) 3.0 in Visual C++ 2.0. By the time you finish reading this article, you should be able to convert your dialog boxes with little effort.

Converting the dialog box

Okay. Take a deep breath and look at the dialog box for entering satellite tracking data (Figure 1).

Figure 1. The Satellite Properties dialog box. The result of designing dialog boxes without the aid of usability experts can be a bit, um, cumbersome.

Converting this dialog box to a property sheet consists of the following steps:

1. Group the information in the dialog box.

2. Create each property page using the resource editor.

3. Use ClassWizard to create a derived class for each page.

4. Create and initialize your property page objects and create the property sheet itself.

Step one: Group the information

To convert the existing dialog box into a series of pages for a property sheet, first take a look at the dialog box and group the settings based on how the user will use the property sheet. When you're satisfied with the groupings, you can proceed.

Step two: Create each property page

Use the resource editor to create a dialog box for each property page. The first page you add to the property sheet determines how much space to allocate for the other property pages in the property sheet. Make sure it is as large as the largest page that you need. First open the original dialog box, delete the OK and Cancel buttons, and select the controls that you want for a page. Then copy and paste them into the dialog box.

The identifiers for the controls in the original dialog box are the same as the identifiers for each control in the tabbed dialog box. And pasting them means a lot less work for you later because you don't have to keep track of each new ID.

Set the dialog box styles to standard property page styles. In the Styles page, use the Style list box to set the style of the dialog box to Child; set the Border list box to Thin; and check the Disabled and Titlebar check boxes. Then switch to the General page and enter the text for that tab into the Caption edit box.

Step three: Put ClassWizard to work

Now use ClassWizard to create a CPropertyPage-derived class for each page. To do this, select the dialog box resource, choose ClassWizard from the Project menu, and then choose CPropertyPage as the base class in ClassWizard. By default, ClassWizard will create a .CPP file and an .H file for each of these new classes. As a result, you will have two files for each new class. Include header files at the beginning of the file to make the call to create the property page. If you included a special header file for the original dialog box, remove it.

When you create these classes, you should consider creating the member variables to hold the values for each control in the property page. In the original dialog box, you can use member variables in each field. To make things a bit easier for conversion, use the exact same names for the member variables for each page.

Step four: Make your declarations and go!

Now you're ready to declare your property pages and your CPropertySheet object. The constructor for the CPropertySheet object can take three parameters: a caption to be displayed in the caption bar of the property sheet window, a pointer to the parent window, and the index of the page to be shown initially. The pointers to the parent window and the index are optional parameters. If you don't pass them to the constructor, the parent window will be the application's main window, and the first page selected will be the first page added to the property sheet.

Add the pages to the property sheet via a call to ::AddPage. Then use ::DoModal to display and run the property sheet. The code snippet below demonstrates these steps.

// Show the editing
// dialog.

int CSatellite::DoEditDialog()

{

// Initialize the
// General page.

genPage.m_strName = m_strName;

genPage.m_dwCatalogNum = m_dwCatalogNum;

genPage.m_iEpochYear = m_iEpochYear;

genPage.m_iLaunchYear = m_iLaunchYear;

genPage.m_dEpochDay = m_dEpochDay;

genPage.m_iEpochRev = m_iEpochRev;

genPage.m_iElementSet = m_iElementSet;

// Initialize the rest of the pages.

.

.

.

// Add each page.

dlgPropSheet.AddPage(&genPage);

dlgPropSheet.AddPage(&eltPage);

dlgPropSheet.AddPage(&trackPage);

dlgPropSheet.AddPage(&modesPage);

dlgPropSheet.AddPage(&notesPage);

// Invoke the property sheet.

int iRet;

if ((iRet = dlgPropSheet.DoModal()) != IDOK)

return iRet;

// Update the data from the member variables

// in the pages.

m_strName = genPage.m_strName;

m_dwCatalogNum = genPage.m_dwCatalogNum;

m_iEpochYear = genPage.m_iEpochYear;

.

.

.

}

What you get

After doing all of this work, you are probably wondering what the new and improved property sheet looks like. Bear in mind that usability experts didn't help design this. If your company has a usability department, I encourage you to get its feedback about the design of the property pages.

Figure 2 (below) shows the property sheet I created based upon groupings set up by someone who knows something about satellites (certainly not me!). Preferably, all the information the user needs to finish a specific task should reside on one tab. The headings that I chose included a tab entitled "General". This heading is abstract and should be changed to something a bit more descriptive. A better heading might be "Identification". The point is that the heading should be descriptive enough so that the user of this dialog box (who does know something about satellites) would immediately be able to tab to the correct page by reading the headings.

Figure 2. The General page of the Satellite Properties property sheet.

This whole bit of conversion only took me a couple of hours. To some that may seem like a lot of time, but I didn't even write the original code. Had I originally written the code, the amount of time required to convert this dialog box would easily have been under half an hour.

The people who designed the CPropertySheet class obviously went to a great deal of effort to make it relatively painless to convert your dialog boxes into property pages. For one thing, the methods for retrieving information that's entered into property sheets are the same as for dialog boxes. Also, if you've written code for dialog boxes before, you'll find that the code to create and use property sheets is nearly identical.

Nancy Winnick Cluts has interrupted her busy schedule on the international super-model circuit to write articles about Windows 95 shell programming for the Microsoft Developer Network.


The Human Factor: Mailbag Miscellany: Menus and MDIs

Tandy Trower
Director of User Interface Design

March 10, 1995

This month I thought I'd take a break from covering new topics and respond to some comments and questions from previous columns.

File menu

First, I received a letter challenging my statement that it is not necessary to include a File menu in all applications ("Menu, please," Developer Network News, September 1994). The reader insisted that every application for Windows should include a File menu, if for no other reason than to provide a logical location for an Exit command.

This reader is partially correct in emphasizing the importance of the File menu for a majority of applications. But I stand by my assertion that a File menu is not required in every application. The purpose of a File menu is to provide commands associated with handling files, typically for opening, saving, and printing files. Such applications as Calculator or Clock for Windows have no such functions.

Further, while many applications have an Exit command, this command is not a requirement either. In applications such as Notepad, for example, an Exit command on the File menu makes sense. However, for objects such as folders and printers in Windows 95, Exit does not apply.

Exit and Close commands are sometimes confused. Exit implies terminating an application process. Close means to remove a window. They apply to different aspects of the interface, although sometimes they may result in the same effect, such as when you close or exit the primary window of a data-editing application. For example, closing a printer window does not terminate the printing process.

As application design becomes more data-centered, applications will be less visible in the interface. As a result, application functions such as Exit will disappear from many menus as windows represent the data or document object rather than the application.

So a File menu is a good thing to have when file operations are supported in your interface. Similarly, Exit is a common command for many application designs. But there are definitely circumstances where neither may be appropriate.

MDI alternatives

The next two questions came in response to "It's Windows 95: Do you know where your child windows are?" (Developer Network News, November 1994), about multiple-document interface (MDI) applications and my suggestion of a few data-centered alternatives.

One reader asked how MDI and "workspaces" differ from a design standpoint. Assuming the reader means from the perspective of UI design rather than coding (the latter being Dr. GUI's specialty), the answer is "not much" and "a whole lot."

To clarify my apparent double-speak, let me first say that visually and operationally there isn't much difference. The child windows share the parent window's menu bar and other interface areas. The child windows are constrained to the parent. When the user closes the parent window, the child windows close as well.

However, the significant difference here is that a workspace is a container. The icons are not representations of minimized windows as you might see under Windows 3.1. Instead, the icons represent objects that are stored in the workspace.

For example, in a Microsoft Word document, you can create a Microsoft Excel embedding that is displayed as an icon. Icons that appear within a workspace represent objects that are embedded (wholly contained) within the workspace. That is, they are literally stored there.

In contrast, traditional MDI only provides visual organization. In other words, Word documents are not literally stored inside the MDI parent window. Another way to think about this: A workspace is like a folder that uses MDI conventions for managing objects opened from within it. In a workspace, there is a one-to-one mapping between storage and the windows that appear within the parent window.

Documents, not links

Another reader asked whether the "workbook" example assumed in-place editing of OLE-linked objects, something not supported in OLE 2.0. The answer is no. If you look at the illustration below, all the tabbed pages were intended to represent individual documents, not links.

Example of a workbook.

However, that does not mean that different tabbed pages could not represent some form of linked data. In Microsoft Excel 5.0, a user can create a chart (linked to data on a spreadsheet page) as a new "page" within the same book.

Possibilities, not specs

Let me reiterate that the examples in my MDI column are only possible designs, not fixed specifications. In addition, these designs are not limited to organizing and viewing documents or files. For example, a workbook's pages could represent different views of the same file.

Thanks for all those cards and letters. Now you know that I actually read them!

Tandy Trower is the director of UI design at Microsoft (or the Curmudgeon of Consistency or worse).


Microsoft Readies Visual FoxPro 3.0

Development tool charts strategic path to Windows 95

March 10, 1995

Microsoft recently announced details of Microsoft Visual FoxPro version 3.0—an advanced relational database management and development tool—for the Windows operating system.

Scheduled for release this spring, Visual FoxPro 3.0 will feature a 32-bit, object-oriented development environment for rapid application development with enhanced client-server capabilities.

"Visual FoxPro 3.0 is a major step forward for the Xbase community," said Roger Heinen, senior vice president of the developer division at Microsoft. "It enables developers to take advantage of Microsoft's solutions platforms, including Windows 95 and Microsoft BackOffice, by seamlessly bringing their existing applications forward and then allowing them to integrate object-oriented and client-server functionality."

Visual creations

Although Visual FoxPro 3.0 lets developers code objects and classes from scratch at the command line, it also allows them to create classes visually.

The Visual Class Designer PowerTool eliminates the need to learn a new development syntax for classes. With it, developers can create classes visually by dragging and dropping controls and attaching code to those controls.

Because the object model in Visual FoxPro 3.0 fully supports inheritance, any changes to the parent class will automatically update every instance of the class wherever it is used. Developers can choose to use subclassing to protect properties from inheritance. It also fully supports encapsulation and polymorphism.

Integration via OLE

Visual FoxPro 3.0 supports OLE services, helping developers build custom applications quickly. It includes OLE Automation, which enables it to control programmatically other business tools such as Microsoft Office business productivity applications.

Visual FoxPro 3.0 also supports the new 32-bit OLE Controls architecture. This provides access to a wide range of additional features and functionality in hundreds of prebuilt components from third-party vendors.

In addition, Visual FoxPro 3.0-based applications can contain OLE objects. Users, for example, can edit "in place" an embedded Microsoft Excel spreadsheet chart or Microsoft Word document without leaving the Visual FoxPro 3.0 application.

Smoothing the way to client-server

Visual FoxPro 3.0 builds client-server connectivity tools into the product, allowing companies to create client-server applications that combine its functionality and graphical user interface with the speed, portability, data storage capability, and built-in security of an open database connectivity (ODBC) data source or server.

Visual FoxPro 3.0 will ship with the newest 32-bit ODBC 2.0 drivers. These drivers deliver data to applications from multiple database and file formats, including Microsoft SQL Server version 4.2; Oracle6 and Oracle7; dBASE III and dBASE IV; Microsoft Access versions 1.x and 2.0; Paradox versions 3.x and 4.0; Microsoft Excel versions 3.0, 4.0, and 5.0; Btrieve; and formatted text files. ODBC database drivers are also available from 140 additional vendors, providing ODBC access for more than 55 database formats.

This new version allows users to update back-end data directly from their desktops. By bringing snapshots of information from the back-end server, it allows users to manipulate the data locally. Only when additions or modifications to the data have been made does the user send a snapshot of the updated information back to the server, greatly reducing the network traffic in client-server environments.

In a multiuser environment where users attempt to make changes to records on the remote server at the same time, Visual FoxPro 3.0 will automatically inform users of incremental changes to the data.

Another benefit is the ability to create parameterized views, which minimize the amount of data pulled down from the server. Users can, for example, specify a parameter such as "only customers in the state of California" and then update the live back-end data from the front end.

Complete backward compatibility

Visual FoxPro 3.0 has a three-pronged migration strategy to protect companies' investments in Xbase solutions and training.

First, it will run any legacy application that runs under FoxPro 2.6. In addition, developers can use a built-in converter to bring FoxPro 2.x screens and projects to the 3.0 format automatically. They can also move gradually to an object-oriented programming paradigm by modifying FoxPro 2.6 code on a property-specific basis, thereby learning the new object syntax from the pure coding perspective.

Visual FoxPro 3.0 is a fully 32-bit tool that will run on either 16-bit or 32-bit Windows operating systems—including Windows 3.x, Windows for Workgroups, and Windows NT—as well as the upcoming Windows 95 operating system. Similarly, solutions developed in Visual FoxPro 3.0 will by default be fully 32-bit, but will also run on 16-bit Windows-based systems.

More information

Pricing information will be available when Visual FoxPro 3.0 is released this spring. Users who purchase FoxPro 2.6 for Windows between January 16, 1995 and the Visual FoxPro 3.0 shipment date will qualify for a no-cost upgrade.

For more information about Microsoft products in the United States, contact your local reseller. In Canada, call the Microsoft Canada Customer Support Centre at (800) 563-9048. Outside the 50 United States and Canada, contact your local Microsoft subsidiary.


New Windows Setup Guidelines: Little Pain, Lots to Gain

Make a simple setup integral to your architecture

Jerry Drain

March 10, 1995

Why follow the new Windows Setup guidelines in writing your application's Setup program? Because otherwise it's money out of your pocket.

Ask any company in our industry to identify the biggest revenue drain, and you will hear support costs mentioned. The biggest generator of support calls is setup/configuration questions.

Microsoft has spent considerable time and cost in usability testing to develop Setup guidelines that do more than just reflect how to write a SETUP.EXE. They show how to take advantage of new features in the Windows 95 operating system, thus offering you a competitive advantage.

Two recurring themes of Windows 95—"making it easy" and implementing value-added features to your application—illustrate the notion behind the Setup guidelines as well as logo programs, the Plug and Play standards, and many other technologies.

Following are some of the reasons for the Setup guidelines (which also apply to Windows NT and Win32s), and some things to consider before writing your Setup application.

Before writing setups

Basically, Setup is the software Plug and Play for an application. There are many Setup programs in the industry—some good, some bad. Customers want consistent Setup applications, a reduced learning curve, better disk management (less confusing, better use of space), and a clean way to remove previously installed files. They want a no-hassle Setup: just plug it in, and it works. And corporate information systems managers want more: flexibility, options, and silent, remote installation of applications across a corporation.

You should consider Setup while designing the architecture of your application, not afterward when many advantages may be difficult to implement. Some important questions to ask include:

• Do you want your application to take advantage of special hardware? If so, check for its installation and configuration in the registry.

• Do you want to run off a CD or a server?

• How much remote administration do you want to support? You should at least provide a silent install and uninstall. Consider exposing configuration information in the registry and allowing remote administrators to configure it.

• Where should you put your files? This is too big a topic for in-depth consideration here. In general, don't use the \SYSTEM subdirectory, which is easily overloaded. Place your files in subdirectories as suggested by the Setup guidelines, and only expose such files as executables and uninstalls to the user's view.

• Which of the new shell features do you want to support?

• Do you have run-once code, which you can put in your SETUP.EXE rather than in your application? This is a great way to decrease size requirements if you don't copy SETUP.EXE to the computer.

• What types of Setup options should you provide? Four are suggested: "Compact," for laptop and low-disk-space configuration; "Custom," to allow all possible options; "Typical," which should provide the intelligent default for most users, and a "Silent" install (see below).

Why an uninstall?

Uninstall is one of the most frequently requested features of an application, so important that it is one of the Windows 95 logo requirements. Because many applications share resources and make modifications throughout the system, deleting an application is rarely a matter of deleting files in a single subdirectory. Users want this feature so they can remove cleanly and reinstall to correct problems, change configurations, or upgrade applications. Users also want the uninstall option so they can free up disk space, or so they can abide by licensing agreements by cleanly deleting an application from one machine before installing it on others.

Some suggestions for uninstall: Maintain a use count in the registry for shared files. (It's simple; the guidelines show how and where.) When you install your application, increment this use count. When you uninstall, decrement it.

If yours is the last application using this file, prompt the user before removing it. If everyone follows this rule, the user will have better disk optimization. In a worst-case scenario, the use count will be artificially high, and the system will have an unused file.

There is a new feature: a Control Panel applet that will run your uninstall for you. This feature requires only two entries in the registry to indicate how the application should be uninstalled.

Microsoft provides an easy way to do an uninstall via the InstallSHIELD technology in the Win32 Software Development Kit (SDK). (See "InstallSHIELD technology helps speed Setup," below.) However, it's easy to do your own, too. In brief: directly execute an application that deletes appropriate files and registry entries and decrements appropriate use counts.

Install and uninstall silently

Make sure to provide a "silent" switch. Truly silent, or unattended, install and uninstall are critical for information systems managers who want to install your application across their corporations, and for original equipment manufacturers who want to do a pre-setup of your applications on their computers. These must operate in an unattended mode.

While running in silent mode, your install and uninstall must be void of pop-up queries or error messages. You will have to provide intelligent responses to these pop-ups as a default. Remember, there may not be a user at the target computer; or, worse, a user will be terribly confused if, while running another application, a pop-up from your install or uninstall occurs. Another issue is to avoid the need to reboot the computer.

Test your silent operations with various systems management applications. Their requirements may vary somewhat. For instance, Microsoft's Systems Management Server product requires a PDF file (which tells which files to copy locally, and how to run the Install app) and an MIF file (an inventory file for the local computer). Details on these will be in the Systems Management Server SDK, which is expected to be released in May on the Developer Network Development Platform.

Using the registry

Another Windows 95 logo requirement is to use the registry instead of making entries into the WIN.INI file. Indeed, Windows 95 does not need an AUTOEXEC.BAT, CONFIG.SYS, or WIN.INI for 32-bit applications, and they are supported only for backward compatibility for 16-bit applications. The Setup guidelines explain in detail how to use the registry, but there are some rough guidelines.

Almost everything that you used to put in an .INI file should now go in the registry. Per-Application-Path in the Windows 95 registry has replaced PATH in AUTOEXEC.BAT.

You no longer need to preload drivers with a CONFIG.SYS; you should dynamically load and unload them for your application. You can use the registry to store any kind of binary data, but don't use it to store huge files such as bitmaps; instead, put a pointer in the registry to that bitmap. Put information for remote configuration in the registry. Also enter any new file types you have in the registry.

If your application supports OLE, you will need to put OLE information in the registry as well. All OLE servers should conform to the OLE Self-Registering Server Specification. (See the OLE Control specifications, which are on the Developer Network Development Platform.)

Cross-platform issues

Microsoft's goal for the Setup guidelines is to provide direction on how to write a single Setup and Uninstall program that works on all the 32-bit platforms: Win32s, Windows 95, Windows NT (Intel, MIPS, Alpha AXP, PowerPC), and future versions of Windows NT. Everything you've read up to here applies to guidelines for these platforms; but because Windows 95 offers a different shell and new functionality, here are some caveats for Windows NT and Win32s:

• You must continue to use dynamic data exchange (DDE) with Program Manager, and your new groups should only expose executables and uninstall.

• Per-Application-Path will not be implemented until the Windows NT Cairo time frame.

• Windows NT and Win32s do not have the Uninstall applet in Control Panel, so you must provide your own icon for your uninstall registry.

Points for installation applications

• Follow the Setup guidelines, and remember that the number one goal is to make it easy.

• Think about Setup early in the design of your application.

• Provide an uninstall.

• Provide silent options for your install and uninstall.

• Use the registry, not .INI or system configuration files. Add entries for your applications, files, and file types. Make your application "remotable."

• Work well with the shell. Follow the guidelines on where to put your files.

Jerry Drain is a member of Microsoft's Developer Relations Group, where he works with ISVs on Windows NT and Windows 95.

InstallSHIELD Technology Helps Speed Setup

Microsoft has recently licensed technology from Stirling Technologies, and has included the InstallSHIELD, SDK Edition, in the Windows 95 SDK to make following the Setup guidelines easier. If you just want to write a quick and simple Setup, using InstallSHIELD is the way to go. Stirling also offers an InstallSHIELD, Professional Edition, that has more tools (such as a debugger) and better internationalization tools. The SDK Edition is a subset of the Professional Edition.

The SDK Edition handles registry manipulations; has a scripting language; provides uninstall functionality and silent option for setup and uninstall; is enabled for double-byte character set (DBCS); puts files on and provides compression for shipping media; and has samples a developer can modify.

The current release of the SDK Edition runs on Windows 95 and Windows NT for Intel. Microsoft is working closely with Stirling to ensure that versions of Windows NT for Alpha AXP, MIPS, and PowerPC will be available shortly after the Windows 95 release, and is also working on a version to ensure a 32-bit Win32s solution as well.

Whether InstallSHIELD will be the Setup toolkit of the future hasn't been determined yet. The Stirling solution is certainly an effective tool for solving today's Setup problems on Windows 95 and Windows NT (Intel). However, Microsoft is also working to improve MS-Setup (which is currently available on Windows NT). Which toolkit ships in future SDKs depends on which tool will best solve the problems that come up while implementing new innovations on the Windows platforms.

Contact Stirling Technologies in the United States at (708) 240-9111 for more information about its InstallSHIELD, Professional Edition; or for a hard copy of the Stirling SDK or a Stirling annotated version of the Setup guidelines. The online copy of the Stirling SDK documentation is in the Win32 SDK.


Putting on an International Interface

Tips on designing UIs that can be accepted around the world

Nadine Kano

March 10, 1995

There are two basic rules for designing a user interface that is internationally acceptable and easy to localize. First, use generic graphics. Second, avoid overcrowding.

The Windows Interface: An Application Design Guide for Windows 95 and Windows NT (Microsoft Press) gives clear recommendations for designing a consistent, easy-to-follow user interface that should result in a program suitable for international markets.

Bitmaps and icons

Bitmaps and icons are a standard feature of Windows-based applications, especially on toolbars. It takes creativity to come up with bitmaps specific enough to identify a setting or operation, yet free of cultural references and stereotypes that don't translate well.

Coming up with different bitmaps for different language editions of a product, however, is a waste of time. A good way to avoid this time drain is to take advantage of either the common toolbar button illustrations defined for Windows 95 or existing international symbols, such as those used on road signs or in airports.

Remember to keep bitmaps simple. The more complex they are, the more difficult they are to decipher. In general, it's a good idea to keep bitmaps clear of letters that represent the first letters of commands (for example, O for Open), and punctuation marks whose meanings may change from locale to locale, such as quotation marks.

Also, don't make text part of bitmaps or icons unless it won't be translated (for example, your company name). Instead, draw text on buttons using the Win32 TextOut call, or take advantage of the ToolTips feature provided by the Microsoft Foundation Class Library (MFC).

It's a good idea to be cautious with representations of animals, religious and mythological symbols, national emblems, colors, people (especially racial, cultural, or gender stereotypes), hand gestures, and body language, which may be misinterpreted or may offend users in another country.

Avoid pictures of sports equipment, utensils, national monuments, or any symbols that might be familiar to some cultures but unfamiliar to others. Pictures that represent a play on words in one language may be completely meaningless in others. Also, keep in mind that not all cultures read text from left to right. A picture of an arrow pointing to the left, indicating "undo," might be confusing to an Arabic or Hebrew speaker. The following illustrations show bitmaps that would probably be confusing to many users.

Take a cultural sounding

Try to be culturally sensitive when choosing sounds for your program as well. Users in the United States, for example, may find it helpful to hear a beep when they make a mistake, but users in Japan may find a beep embarrassing, because it calls attention to their blunders. Sometimes the meaning or images associated with certain sounds vary from country to country. Telephones and sirens, for instance, have different sounds in different countries.

For non-multimedia applications, sound should be a secondary method for sending messages to the user anyway, because some software users are hearing impaired, don't have sound-generating equipment, work in a noisy environment, or prefer to have sounds turned off.

Menus and dialog boxes

The length of English text often grows when translated. The English word "Edit" becomes "Bearbeiten" in German, and "Sort Ascending" becomes "Lajittele nousevassa järjestyksessä" in Finnish. So, design menu bars, status bars, toolbars, title bars, and dialog boxes to allow for this expansion. Limit the number of menus on your menu bar so that the bar does not wrap to a second line when translated.

Abbreviating main menu names on the menu bar is rarely acceptable, although abbreviating words on status bars is common. Keep in mind that in some languages even abbreviations require more space than in English, and that in ideographic languages, such as Japanese or Chinese, abbreviations often don't exist.

Sometimes you can use symbols to represent words. In Europe, for example, it is acceptable to translate the English word "Help" as a question mark (?) to save space.

Dialog boxes crammed full of information will not fit on the screen when translated into some languages. You can use the tabbed dialog controls available in Windows 95 to minimize this problem (see illustration below). You should also employ multiline text boxes to display messages or multiple-word descriptions that will become long enough to wrap in some languages. If you're not sure whether a menu or dialog box design will work sufficiently for several languages, have someone translate a few examples and then double-check.

Use Windows 95 tabbed dialog controls to keep dialog boxes from becoming too large.

Keying in on the keyboard

Keyboard differences also pose potential problems. Keyboard layouts change according to locale. Not all characters exist in all keyboard layouts. When assigning shortcut key combinations, make sure you can reproduce them using international keyboards, especially if you will be shipping an unlocalized product to countries with widely differing keyboard layouts. You can choose from a number of different keyboard layouts via the Windows Control Panel.

Most European keyboards contain an "AltGr" key (usually the right ALT key), which can be used to access a third character on some keys. On some keyboard layouts, ALTGR is used to produce basic Latin letters. On the Polish keyboard, for instance, you have to press ALTGR to generate accented forms of the letters A, E, C, N, S, L, O, and Z.

Pressing the altgr key sends Windows the same virtual key codes as pressing CTRLl+ALT. Don't make characters that are produced with ALTGR or SHIFT+ALTGR on some keyboards part of CTRL+ALT or SHIFT+CTRL+ALT shortcut combinations (it won't work because Windows can't parse the extra CTRL and ALT virtual key codes). The CTRL+ALT+[ shortcut key combination, for example, cannot be reproduced on Canadian, Portuguese, Swedish, or Spanish keyboards, among others, because on these keyboards the [ character is produced with the ALTGR key.

Other keyboard combinations are reserved for system use by some editions of Windows; ALT+~ invokes input method editors on systems in the Far East. Steer clear of the following characters when assigning shortcut keys:

@ £ $ { } [ ] \ ~ | ^ ‘ < >

Consider using numbers and function keys (F4, F5, and so on) instead of letters in shortcut key combinations. These combinations are not as intuitive for the user as letters, but they don't have to be localized. Using combinations that can be produced with the keyboard of the target locale will accommodate most users, but bear in mind that some locales, such as the Netherlands, Eastern Europe, and Arabic- and Hebrew-speaking countries, use more than one standard keyboard. Using numbers and function keys becomes even more appealing when you consider the ability to use multiple keyboards introduced with Windows 95, because virtually all keyboard layouts include numbers and function keys.

This article is adapted from Developing International Software for Microsoft Windows by Nadine Kano. It will be published by Microsoft Press in spring 1995.

Nadine Kano is a globalization guru in the Developer Relations Group. She has typed her fingers to the bone writing a guide to developing international software for Microsoft Press.


Tap into the Developer Network CompuServe Forum

March 10, 1995

What happens in the Microsoft Developer Network forum (GO MSDN) on CompuServe?

Lots! For example, you can jump into the Peer Help/Chat Messages section to post questions or answer inquiries from other developers. In Library 1, "New Uploads," you'll find things that didn't make the last issue of the Development Library or Platform, such as the international terminology glossaries. You can also find the MSDN FAQ, a compilation of answers to the most frequently asked questions we receive.

We also sometimes post "flashes" highlighting items of importance to developers. If there is a flash, you'll automatically get it upon entering the MSDN forum. We also use the CompuServe forum to obtain your feedback and responses to surveys, particularly when we face hard decisions. For example, your input was invaluable in figuring out how—or even if—we should go to two CDs for the Development Library. When we post surveys, you are notified via flashes. You can also talk to us via the MSDN forum. Let us know if we're doing well or abysmally, and how we can improve.

For more information on CompuServe within the United States, call (800) 524-3388 and ask for representative 230. Outside the United States, call (+1) (614) 529-1340 and ask for representative 230.


Visual Basic: Tips and Tradeoffs in Data Access Performance

Robert Eineigl

March 10, 1995

When Visual Basic version 3.0 arrived, with its rich set of data access capabilities, the increased power and flexibility also provided, in terms of performance, more rope to hang yourself with (pun intended!). When Visual Basic 3.0 became the predominant platform for building clients for mission-critical, vertical data access systems, many programmers experienced the joys of system analysis and database management for the first time.

As easy access to information becomes more essential to remaining competitive, it also escalates expectations and makes system users increasingly impatient with unresponsive client applications.

This article surveys the many choices available to the programmer writing data-centric applications in Visual Basic, and offers recommendations aimed at maximizing the perceived responsiveness and performance of data access client applications.

The choices

From a design perspective, the programmer of a data access client application faces four major choices affecting performance:

• Which back-end relational database to use.

• Which data access method to employ—whether to use the Visual Basic data access object (DAO) layer, open database connectivity (ODBC), or a proprietary back-end interface or interfaces.

• Which back-end database system design data model to use, with its associated triggers and procedures.

• If using the DAO layer, making the correct choice of data access objects, and where to use transactions, attached tables, and the pass-through flag.

By using speed and efficiency as the scalpel, the endless feature requests for the system can be pared down to a finite, implementable list. Keeping performance implications at the forefront of the design process helps narrow choices and develop an architecture that is both scalable and responsive. Performance considerations should be second in priority only to the critical analysis needed to define clearly the rules of the business that the system must satisfy.

First choice: Which RDBMS?

The choice of a relational database management system (RDBMS) depends on both present and future business needs, as well as resources available. This decision is logically the starting point for the system design, because all the decisions pertaining to performance depend on the capabilities and limitations of the back end.

Several questions need to be considered:

• How many users will the system serve, now and in the next two years?

• Does data need to be distributed to more than one site?

• How often can the system requirements be expected to change? How quickly will those changes need to be made?

• What level of expertise is reasonable to expect from users?

• What resources are available to purchase hardware, software, and development/training time?

A comprehensive discussion of the tradeoffs involved with this first area of choice is beyond the scope of this article. However, let me propose a simple scenario for the purposes of illustration. Let's assume these answers to our checklist of questions:

• 70 users now, increasing to as many as 150 users in two years.

• Yes, there's a need for distributed data.

• The system will need revision every six months.

• All users are novices to database concepts.

• Money is available for a dedicated server box, a site license for SQL Server for Windows NT, and sufficient development time if Visual Basic is used as the front-end development tool.

The answers here favor a true client-server RDBMS, especially because of the large number of users anticipated and the need for administrative tools for data replication. A dedicated server is essential to multiuser systems with more than 50 users. Client-side database engines, such as Microsoft Access, also require that all clients voluntarily close their connections to the .MDB file before the database can be copied, compacted, and so on.

The need for frequent or fast system revisions also favors a dedicated back-end approach, with the rules of the business stored in the back end. Making system changes is easier to accomplish and synchronize from one central location.

Second choice: Which data access method?

With Visual Basic as the front-end development platform, there are several methods of data access:

• Write code that leverages the built-in DAO layer, directly to Microsoft Access, FoxPro, dBASE, Btrieve, and Paradox databases or through the DAO to ODBC databases.

• Code directly to the ODBC API, bypassing the DAO, starting with sample code from the ODBC SDK.

• Code directly to a back-end-specific protocol, such as the VBSQL library for SQL Server or a gateway to a mainframe database.

When to use the DAO layer

The Visual Basic DAO layer was designed to provide a generic set of data-aware objects and functions for use as a built-in library. This design insulates the programmer from the proprietary details of the back end. In the case of ODBC databases, the DAO layer provides the interface to the ODBC API. If the databases are local or client-based, such as Microsoft Access or FoxPro, the DAO layer provides a single interface, via the Microsoft Access engine, to the divergent database formats. The generic DAO layer in Visual Basic provides the leverage of a built-in data-aware library. Its disadvantage is that you can't modify or extend that library's functionality.

(Because using database objects raises some complicated issues, I will discuss how to use the DAO layer efficiently in the May/June 1995 issue of the Developer Network News.)

Go directly to the ODBC layer...

If the system must access heterogeneous data sources and be scalable enough to add new data sources as needed, the advantages of the ODBC approach should be apparent.

If the choice is made to code directly to the ODBC API, the development process can be similar to using the DAO layer, once the investment in creating a generic data access library or engine is made. The leverage begins once this ODBC interface library is written, because the Visual Basic code can be generic and insulated from the proprietary details—in the same way as code written to the DAO. And as with the code written to the DAO, the Visual Basic code written to the homegrown ODBC library is reusable as target back-end databases change.

Because Visual Basic and Microsoft Access were the first high-volume applications to exploit the ODBC standard, the general first impression of the ODBC mechanism was that it was much slower than the proprietary access protocols. In reality most performance decreases could be traced to one particular ODBC interface: the Microsoft Access engine.

This engine was designed for high generality and to provide a generic library of data access functions to make Visual Basic code written to the DAO independent of the data source. To achieve this, some flexibility and optimization for specific functions were sacrificed.

In bench tests against Microsoft SQL Server, comparing direct ODBC calls to VBSQL(DBLIB) calls, the average performance numbers were comparable, with some ODBC functions being faster than some DBLIB calls and vice versa. Getting a connection through the ODBC API, for example, took longer than through VBSQL calls, though not by an order of magnitude.

...or to a proprietary protocol

For application architectures where connections are created, used, and then immediately broken, the bench test results would seem to favor the proprietary protocol. Bear in mind, however, that this architecture arose from the need to "go easy" on older operating systems and networks, and may be less imperative with the latest operating systems/networks.

If the set of data sources is limited for the foreseeable future, having several proprietary libraries coexist in the front end may be the best solution. This leverages existing expertise and investments to get a production system up as soon as possible. In this case, maintaining the performance level of existing legacy systems in any new system is the appropriate choice.

Third choice: Which database design?

The actual design of the database—including normalization of tables, architecture of stored procedures, security, and data integrity—is a major area for performance considerations. Designing database systems for optimal performance is a broad topic; here we consider only questions directly affecting Visual Basic developers.

Assuming that we are discussing systems using client-server databases, the first architectural decision is how much processing logic should reside in the Visual Basic application, in the back-end, or in intermediary layers. For example, should the front end perform all data validation, none, or a mixture of front- and back-end logic based on performance considerations?

Other architectural decisions: Should the client handle security separately from the database's intrinsic security model or leave it entirely to the back-end's security model? Should the user's preferences be stored locally in an .INI file or on the back end in a user preferences table?

The answers to such questions have performance implications, as do the more back-end-centric issues of data modeling, enforcing business rules, or optimizing transaction throughput. These design decisions can only be made in the precise context of the particular project. Generally, programmers can increase the overall client performance by letting the client and server each do what it can do fastest, provided that doing so doesn't violate any architectural specifications for the system.

Next issue

Keeping the performance tradeoffs in mind during design of Visual Basic data access systems can reap large performance gains. In the next Visual Basic column, I'll discuss which DAO object is appropriate for which task, where to use transactions, when to use the pass-through flag, and when to use attached tables.

Robert Eineigl works in Microsoft's Information Technology Group, building database systems coupled to clients written in Visual Basic. He also disturbs wildlife by playing his custom-made, oversized trumpet.

Additional Reading

Note: All of these articles are in the Developer Network Development Library.

"Summary article: INF: Article List for Visual Basic: Data Access w/ MS Access/Jet" ID: Q122723

"LONG: Overview of Data Access in Visual Basic Version 3.0" ID: Q108379

"Using Table Objects Versus Dynaset/Snapshot Objects in Visual Basic" ID: Q109218

"INF: Database Normalization Basics" ID: Q100139

"Differences Between the Object Variables in Visual Basic Version 3.0" ID: Q103442

"Differences Among the Installable ISAMs" ID: Q104918

"Comparison of Seek Versus Find Methods, for Visual Basic Data Access" ID: Q108149

"How to Speed Up Data Access by Using BeginTrans & CommitTrans" ID: Q109830

"How to Optimize Memory Management in Visual Basic 3.0 for Windows" ID: Q112860

"How to Access Multiple Databases in an SQL Query" ID: Q113701

"PRB: ODBC Error ‘Connection is busy with results...'" ID: Q119023

"LONG: Visual Basic 3.0 EXTERNAL.TXT: Using External Database Tables" ID: Q108422

"LONG: PERFORM.TXT—Performance Tuning Tips for Visual Basic and MS Access" ID: Q107751

"INF: Five Parameters to Set in ISAM Section of MSACCESS.INI" ID: Q101323


Visual C++ 2.1: New Classes, Samples, Drivers, and More

First CD subscription release brings latest technology

Jonathan Kagle

March 10, 1995

What's new with the Microsoft Visual C++ development system? The big news is the availability of Visual C++ version 2.1, the first release of Visual C++ 2.0 Subscription Edition for Intel platforms.

Visual C++ 2.1 gives new functionality to the Microsoft Foundation Class Library (MFC) for both the 32-bit and 16-bit versions. The new release also adds features to the OLE Control Developer's Kit (CDK), including the ability to use MFC database classes in OLE Controls. It also includes new samples, documentation, and, of course, bug fixes.

New features

The following features have been added to the editors and wizards in this version of 32-bit Visual C++:

• Dialog editor support for new Windows common controls. You can add spin button, tab, tree view, and other common controls to dialog boxes in your Windows 95-based applications. If you want to add Windows common controls to your application, you must be running under the same operating system on which the target application will run. For example, you can develop an application under Windows NT 3.5 that will run on Windows 95, but you cannot include Windows common controls. (This will change shortly with the release of Windows NT version 3.51.)

• ClassWizard support for new Windows common controls. You can map control notification messages to MFC handler functions, and add classes derived from Windows common control classes. ClassWizard's improved layout makes these tasks easier.

• AppWizard support for simple MAPI (the Windows messaging API) and Windows Sockets.

• Complete AppWizard support for OLE Automation in a dynamic-link library (DLL).

• AppWizard support for creating a USRDLL project. AppWizard can now provide you with a skeleton CWinApp-derived object, rather than a DllMain function, as it does when creating an MFC extension DLL.

New features in 32-bit MFC

The following features have been added to MFC in the 32-bit product:

• New Windows common control classes. Currently you can use these controls only in applications that will run under Windows 95. They will also be supported by future versions of Windows NT (starting with Windows NT 3.51) and Win32s.

• Support for simple MAPI in CDocument and COleDocument classes.

• Windows Sockets classes for network programming (CAsyncSocket, CSocket, and CSocketFile).

• New 32-bit open database connectivity (ODBC) drivers for use with the MFC database classes (see the list of drivers, below).

Updated 16-bit version

This release also contains 16-bit Visual C++ version 1.52, an update from version 1.51, which shipped with Visual C++ 2.0. Visual C++ 1.52 runs on Windows version 3.1 or later and Windows NT version 3.5, and includes the 16-bit MFC version 2.52.

Besides OLE and database classes, this version includes classes for OLE control development and a number of new MFC 2.52 classes ported from the 32-bit product.

Like the 32-bit product, new features in MFC 2.52 include support for simple MAPI in CDocument and COleDocument classes; Windows Sockets classes for network programming; and new 16-bit ODBC drivers for use with the MFC database classes (see the list of drivers, below).

In addition, the 16-bit version now includes CPropertySheet and CPropertyPage, MFC classes that support "tabbed dialog boxes"—known as "property sheets" in MFC. Previously, these were available only in 32-bit Visual C++ 2.0.

New to the OLE Control Developer's Kit

The following features have been added to the CDK:

• Support for using the MFC database classes in OLE Controls. This allows you to create data-access controls using CDatabase and CRecordset classes. The database support also includes a sample program, called DB, that illustrates the use of the MFC ODBC database classes in an OLE control.

• OLE Controls that work under Win32s.

• Performance improvements, particularly in the areas of control creation and property access.

• Support for "grab handles" when controls are active.

MFC Migration Kit

Many developers have existing applications for Windows written in C. To help these developers migrate their applications to C++, Visual C++ 2.1 includes the MFC Migration Kit. The kit includes:

• An extensive MFC Migration Guide, a Help file that takes you through the migration process with both 16-bit and 32-bit sample applications using MFC.

• A migration tool (in 16-bit and 32-bit versions) that scans your C-language source code and suggests things you should do to migrate the code to MFC.

• Both 16-bit and 32-bit sample applications—before migration, in C, and after migration, in C++.

The migration tool can also help you port 16-bit applications to 32-bit, with or without MFC. The MFC Migration Guide explains where that port fits into your migration strategy.

The Visual C++ subscription program is designed to distribute all these improvements quickly and efficiently. But what if you can't buy the subscription edition because you live outside the U.S. or Canada? The Visual C++ subscription is now being launched in Western Europe. Outside Europe and North America, the CD will be available as a stand-alone upgrade through your local subsidiary. (See below, "Where's my Visual C++ 2.1 CD?")

Note: The documentation for Visual C++ 2.1 is scheduled to be included in the April release of the Developer Network Development Library.

Jonathan Kagle is a product manager for Visual C++ and Microsoft Test. In his spare time, he enjoys whittling, terrariums, and slam-dancing.

ODBC Drivers Included with Visual C++ 2.1 Release

• Microsoft Access (for Microsoft Access versions 1.x through 2.x)

• Btrieve (for Btrieve versions 5.1 and 6.x—only the 16-bit version of this driver is available)

• dBASE (for dBASE versions III and IV)

• Microsoft Excel (for Microsoft Excel versions 3.0 through 5.0)

• Microsoft FoxPro (for FoxPro versions 2.0, 2.5, and 2.6)

• Paradox (for Paradox versions 3.5, 4.0, and 4.5)

• Text (for ASCII text files)

• Microsoft SQL Server version 1.2 or later

• Oracle 6.0 or later (16-bit only)

Where's My Visual C++ 2.1 CD?

You wait by the mailbox day after day, but still your Visual C++ 2.1 CD doesn't arrive. What's the problem? There are several possibilities:

• You have not activated your subscription. Despite rumors to the contrary, Microsoft ESP (extra-sensory perception) for Windows is not yet bug-free, so you must send in the activation card that came in the box (it's cleverly hidden next to the MFC hierarchy chart). If you purchased your Visual C++ 2.0 subscription from your local reseller but have not activated it, please call (800) 719-5577 or send in your subscription activation card. If you lost the activation card, call (800) 719-7577 and have your product ID number ready.

• You live outside the United States or Canada. In European countries, where you can purchase the Microsoft Developer Network, make sure that your copy of Visual C++ 2.0 is registered, because you should receive a mailing that describes how to upgrade to the subscription. If you are in a hurry, you can phone the Developer Network Subscription Centre direct (see "Right Numbers" in the Columns section of this online edition of Developer Network News) to upgrade to the Visual C++ subscription. The subscription is not yet available outside North America and Europe, but a stand-alone version 2.1 should be available from your local subsidiary (part number 048-056-040A).

• You bought the non-subscription edition. If you live in the U.S. or Canada, you can upgrade to the Visual C++ subscription by sending in the upgrade card in the box. If you've lost the card, call Microsoft at (800) 719-5577.

• Something else went wrong. Call Microsoft at (800) 719-5577 with your product ID number.


Why The Microsoft Network?

Easier access and richer content to open online world to users, businesses

John Williams
Microsoft Online Services Group

March 10, 1995

Rapid, efficient information exchange, regardless of time or place, is increasingly central to the lives of a growing number of people. The integration of electronic mail and local area network-based computing has become integral to how a large part of our society functions—so much so that a personal e-mail delivered from across the globe, or the ability to access a file from someone else's PC in another building, is often taken for granted.

Our reliance on this technology suggests how every computer user would benefit, personally and professionally, by having this degree of access.

The recent explosion of interest in the Internet and commercial online services shows that an enormous number of people agree. Internet usage has tripled, and commercial service memberships more than doubled, in the past two years. New providers and offerings appear almost daily.

Yet despite all the hype, more than 90 percent of the PC-installed base remains "unwired." Even if the installed base of PCs didn't grow, the current 20 percent annual growth rate in new online users would result in less than 60 percent penetration in 10 years. Microsoft researched and built The Microsoft Network (MSN) to accelerate the realization of this great opportunity.

Getting connected

The concept of "wiring" together the tens of millions of PCs around the world is not new. The Internet, local bulletin-board systems, and several broadly available commercial online services have been around for more than a decade.

So, Microsoft's first step was to understand the roadblocks to broader market adoption of online services. After two years of research, what the company discovered is a series of fundamental "disconnects" between what current online technology has to offer and what end users and content providers want.

As with any new medium, online services will gain widespread adoption only if they provide uniquely rich and valuable solutions to customer needs, offered in a more compelling and accessible way than the alternatives.

Online service providers such as MSN have two customer bases to which this equation applies: end- user members and independent content providers.

End users want this technology to be easier to access and use. They need more predictable pricing, and the ability to buy what they really need or want. They also need richer, deeper content that is presented in a more robust, compelling manner.

The content and information providers (IPs) need a business model that caters to a wide variety of different businesses and that promises long-term profitability. IPs need to extend brand identities and current assets. They need better tools and information for managing their businesses. And they need the tools and infrastructure to produce and present their offerings in an easily accessible, interesting way.

The Microsoft Network strategy

Together, the existing online technology and its business model hinder widespread adoption by not meeting the needs of either of these customer communities. MSN attempts to answer these needs, and thus provide an environment that expands the overall online services market.

The MSN strategy revolves around four initiatives driven by the needs of its two customer communities:

1. Viable, long-term business environment

MSN's viability rests on the success of content providers to reach and motivate customers. In a nutshell, if they don't make money, MSN won't make money.

Investment by content providers in online technology is the only way the content that reaches end users will improve. To encourage this, MSN has adopted a new, flexible-platform business model that empowers and rewards independent content and service providers.

Existing online services inhibit the way providers can present their information and services, and limit their profits, often to a small share of a shrinking revenue model based on customer online connection-time charges.

MSN provides a new business environment that puts revenue control entirely in the hands of IPs. This means not only control over variable revenue and pricing models—such as subscriptions, online transactions, advertising subsidies, and ticketed events—but also retaining the majority of the revenues generated by their content and services.

2. Easy, inexpensive access

The need to make technology easier to use is magnified in the arena of online technology, where connectivity to and navigation of vast amounts of data are necessary. To that end, access to MSN is a feature of Windows 95.

By extending the feature set and graphical interface of Windows 95, MSN provides a familiar environment that facilitates exploration and interaction in the online world. In all respects, MSN looks, acts, walks, and talks like Windows 95.

For example, services on MSN can be browsed using the Explorer in Windows 95 or from an icon-based container view. Such actions as downloading files are simple drag-and-drop copy operations. Shortcuts enable personalized and efficient navigation. E-mail and rich-text content documents are managed through the Microsoft Exchange and WordPad applications built into Windows 95. And the same familiar user interface carries through all core communication functionality.

MSN also offers affordable access. By adopting a business model that emphasizes member and content activity rather than connect time, Microsoft plans to deliver local phone-call access worldwide at the lowest possible price.

3. A more compelling online experience

Interaction is the lifeblood of online services. How well the environment is produced, and the quality of content depth and presentation, drive a service's ability to attract and retain members.

MSN supports and promotes personalized discovery and investment for members and content providers alike. A new generation of technology and capabilities lets both groups shape dynamic communities around their own interests, products, and services. Experienced, knowledgeable forum managers will facilitate the expansion and diversity of these communities worldwide.

As with the revenue model, control over brand, product, and business extension lies with the content provider. But MSN will facilitate a higher quality of content and services by providing a new generation of content-publishing tools specifically designed to deliver personalized multimedia online content.

4. World-class communication

Access to communication abilities that transcend the traditional boundaries of time, cost, resources, and geography is one of the primary customer needs MSN was designed to deliver.

To meet customer ease-of-use requirements, MSN extends the Windows 95 communication environment through consistent user interface, OLE support, drag-and-drop management, Explorer navigation, and rich-text formatting.

By fully utilizing the Microsoft Exchange e-mail client in Windows 95 and extending this functionality to bulletin board, file library, and "chat" services, MSN offers easy-to-use communication. It was designed from the ground up to accommodate access to the network from anywhere in the world—and exchange of information between members and content providers anywhere in the world.

Bringing it together

MSN represents an opportunity to combine the assets, skills, and tools of the Windows environment with the online world.

The benefits of building MSN on Windows 95 (client) and Windows NT (server) extend beyond ease-of-use and feature-set gains. The long-term potential for the online medium will, like Windows, unveil itself only through the constant innovation encouraged by an open environment.

From linking desktop applications to online components with Shortcuts, to advanced OLE Automation, to custom messaging API solutions, to existing and new standards that drive your current Windows development efforts, MSN is designed to offer new business opportunities. All of this will be integrated and supported through Microsoft developer-service organizations and events beginning this spring.

Because developers will be a crucial part of making this happen, the Developer Network News plans in future issues to take a closer look at business and informational opportunities for developers on MSN, as well as to provide more details on MSN's tools and technologies.

John Williams is the group manager for market development in the Microsoft Online Services Group.


Windows 95 Controls on Windows NT

Windows NT 3.51 adds compression, security APIs, new dialogs, and Help engine

Tammy Steele

March 10, 1995

Windows NT 3.51, scheduled for release around midyear, offers the new common control APIs as seen on the Windows 95 beta, as well as new compression and security features for Win32-based application developers.

This means the controls, dialog boxes, and Help engine on the Windows 95 beta will now be available on Windows NT 3.51. Developers can give their interfaces and Help systems a Windows 95 look in Win32-based applications that work across multiple Windows platforms. This brings us one step closer to the consistent user interface across Windows platforms that we'll have in the near future.

New controls, dialog boxes

The new Windows controls are tree view, list view, rich-text edit, progress indicator, spin button, toolbar, status bar, slider, tab control, wizard, and column header. (For more information on these controls, see "The Human Factor: With Windows 95, you're never out of control(s)" by Tandy Trower, Developer Network News, January/February 1995.) The new dialog boxes are Print and Page Setup, which have been modified. The other dialog boxes, such as Open, Save, Save As, and so on, will continue to operate as they do today on Windows NT but will have the new look when the application runs on Windows 95.

Using these new controls and dialog boxes, you can write Explorer-like applications that look the same whether they are running on top of Windows NT 3.51 or on Windows 95. The Developer Network CHICOAPP sample illustrates this very well. You can find an updated CHICOAPP sample application in the Developer Network Development Library.

New Help, too

Looking for some easy Help? The jazzy new Help model for Windows 95 is a part of Windows NT 3.51 as well. There is a new WinHelp engine—as seen on beta versions of Windows 95—that has full backward compatibility but offers more power and more flexibility, and is much easier to use than Windows 3.1.

The new WinHelp features full-text search and a documented interface, which supports indexing, searching, and compression, and has language-specific dynamic-link libraries (DLLs) for stemming.

It also supports combined Help files with contents, index, find, and associative linking. This new functionality will allow multiple Help files to appear as one to the user. In addition, there's a new Help compiler that makes authoring and compiling Help files easier and faster.

Compression APIs

To support compression on an individual file basis, several compression APIs have been added to the Win32 API. Windows NT 3.51 is the first Windows platform to support them.

Each NTFS (New Technology file system) file and directory will have a new compression attribute. With the attribute on, all of the data in a file is compressed; if the attribute is off, no data is compressed. Because files and subdirectories inherit their parent directory's compression attribute when they are created, users must use the DeviceIoControl function to change the compression status of a file or directory.

Users can also employ the DeviceIoControl function to specify which compression format to employ (for example, LZRW1), or to read and write compressed files without expanding (that is, decompressing) the data. Other compression APIs include GetCompressedFileSize, GetFileAttributes, and GetVolumeInformation.

New service APIs

Windows NT 3.51 also introduces several new service APIs for side logon, RPC (remote procedure call), and network services.

Three new service APIs—LogonUser, ImpersonateUser, and CreateProcessAsUser—were added to solve some logon issues. With these calls, a service can now validate an account, impersonate that user, or create entire separate processes for a particular user. Please be warned that it is your responsibility when using these calls to "secure the wire" for passwords over the network when possible.

The recommended way to write the server portion of a client-server system in Windows NT is to use a Windows NT service. The recommended basic structure of a Windows NT service that provides secure access to its clients looks like this:

• Wait for a client transaction.

• Select thread from pool to perform work for client.

• Impersonate the client.

• Do client work.

• Revert to server security.

• Return thread to pool.

Impersonation allows a thread to assume temporarily the security context of another user. In this way, a mail server could be started in its own security, then switch to the security context of a mail client to do work for that client, and ultimately return to its own security when finished.

While impersonating the client, the mail server wouldn't need to go through complex determinations of what the user could or couldn't do, but instead would allow Windows NT to decide. For example, the server could simply call OpenFile on the client requested. Assuming that the file had previously been set up so that only a particular user and not the mail server could open the file, Windows NT would have the responsibility for allowing access to this file.

Previously, impersonation was available on Windows NT 3.1, but only for those using named pipes between Microsoft operating systems. Servers needing to provide services to a legacy system, needing to abide by a previously published protocol, or wanting to use sockets as a transport mechanism were unable to use impersonation. Under Windows NT 3.51, a combination of LogonUser and ImpersonateUser allows a server to use any transport mechanism.

In addition, Windows NT 3.51 also provides expanded security for RPC mechanisms between many different platforms. Between supported platforms, RPC can now provide everything from no security to connection security to security as strict as full encryption. The implementation of the generic security services (GSS) API in Windows NT 3.51 allows developers to extend the RPC mechanism or other communications mechanisms. The GSS API allows them to use either Windows NT security or other foreign security services in the future.

Windows NT 3.51 has also expanded the Net* APIs to give more capabilities to services and server administrators concerned with user information. These APIs include NetQueryDisplay and NetUserChangePassword.

Replaceable security

Another addition to Windows NT 3.51 allows the replacement of parts of Winlogon, the component of Windows NT that provides interactive logon support. This lets developers modify the interactive logon model. Specifically, the identification and authentication parts of Winlogon are implemented in a replaceable DLL called GINA (graphical identification and authentication).

GINA allows customers, for example, to implement smart-card, retinal scan, or other authentication mechanisms in place of the standard Windows NT username/password authentication.

Stubs for all Win32 APIs

Finally, all of the new Win32 APIs that will be available on Windows 95 but are not yet supported by Windows NT are stubbed in Windows NT 3.51. This means—and you've probably all heard it here before—that now, more than ever, you can write one application that targets all Windows platforms.

For example, say an application wants to call IShellFolder to browse through the Windows 95 name space. IShellFolder's functionality is not supported on Windows NT 3.51, but the same executable can be compiled and can run fine on Windows NT 3.51 because a "NO" is returned when IUnknown::QueryInterface is called. The same is true for API calls, such as the above-mentioned security API, that are supported by Windows NT but not by Windows 95. Those calls are stubbed on Windows 95 and will return ERROR_NOT_IMPLEMENTED when called from an application running on Windows 95.

Tammy Steele is a technical evangelist in Developer Relations. When not playing with her baby boy, she enjoys spreading the Win32 word to developers

(John Hall, a software design engineer in the Developer Relations Group, contributed to this article.)

Coming up: Win32s Versions 1.25 and 1.3

Win32s has been around for quite a while now, and Microsoft tries to keep making it better and better. Win32s is a set of redistributable DLLs and a VxD that allows Win32 applications to run on Windows 3.1 and Windows for Workgroups computers. Since the release of Win32s version 1.2, there has been full 32-bit OLE support as well.

Win32s version 1.25, which is scheduled to ship in March, contains many bug fixes and no longer has the 128K stack limitation. This means developers using the universal thunk, which has a 40K stack requirement, and those porting from nonsegmented operating systems where stack size was not much of a consideration (that is, UNIX or VMS) will be able to develop Win32s-based applications with significantly less grief.

Beyond that, Win32s 1.3 is scheduled to ship with the release of Windows 95 and will contain support for all the new controls (list view, tree view, slider, and so on), all the OLE dialog boxes, and support for the page setup dialog box. In addition, Win32s 1.3 will contain stubs for all Win32 APIs, including those to be introduced on the Windows 95 platform.

A beta of Win32s 1.3 will be available with the Windows NT 3.51 release of the Win32 SDK.

For more information on Win32s, you can search the Developer Network Development Library.


Windows NT Server, SQL Server Dish up a Business Solution for Restaurant Chain

Dianne Calvi

March 10, 1995

In the volatile restaurant business, keeping customers satisfied is a formidable challenge. But it is critical to success. For more than 30 years, Chart House Enterprises, Inc., has upheld a reputation for excellence at its upscale restaurants. The result: Chart House operates 65 restaurants across seven time zones and reports annual sales of $150 million.

The management of the Solana Beach, California-based company attributes much of its success to loyal customers. To reward their patronage, Chart House launched the Aloha Club Frequent Dining Program in October 1993.

Because the program was experimental, Chart House turned to an outside fulfillment house for processing membership applications and dining transactions. Every day, all 65 restaurants had to overnight forms to the fulfillment house by courier. The data was then entered manually from the hard-copy forms into a minicomputer.

From the start, customer-service problems plagued the project. Membership packets took 12 weeks to arrive, applications were lost, and dining transactions were improperly credited because of illegible forms. Worse, customer-service representatives answering Chart House's toll-free number had no access to customer data, which resided on the fulfillment house's minicomputer. To respond to a customer inquiry, they had to fax a request to the fulfillment house and wait—often two or three days—for a response. Recalled John Townsend, director of information services for Chart House, "We did a disservice to customers, probably driving them away from the restaurant rather than encouraging them to come in more often."

Redesign, re-engineer

The Aloha Club problems put Chart House at risk of losing its biggest competitive advantage: excellent personalized customer service. So the firm decided in March 1994 to turn to WinResources Computing, Inc., a San Diego-based Microsoft Solution Provider, to redesign the Aloha Club completely. "Time was critical," said Bob Karp, president of WinResources. "Chart House management realized that the success of the program would be jeopardized if we didn't move quickly, because customer satisfaction with the program was very low."

In less than a month, WinResources completed the requirements analysis and suggested a complete redesign of the system. It identified four key objectives: improve access to the data; develop a system that could easily integrate with future accounting and point-of-sales applications; create an integrated reporting and analysis process; and minimize training costs.

Because Chart House had already installed 486/66 computers running Microsoft Office Professional and a Visual Basic-based menu application at the restaurants, WinResources suggested a Windows NT-based client-server solution.

The Windows NT Server operating system offered 32-bit processing for speed and capacity, along with the data security, reliability, and administrative features found on many high-end minicomputers. It also offered the same Windows-based APIs on both the client and server, which meant that Chart House developers wouldn't have to learn two sets of APIs to develop applications. All this would help Chart House keep development, training, and administration time to a minimum.

SQL Server steps up to the plate

Chart House then evaluated Microsoft SQL Server for membership transaction processing. Because of the scalability of SQL Server and the relatively low cost of the hardware and software, Chart House decided to get SQL Server and a Compaq ProLiant Dual Pentium 90-MHz computer with 128 megabytes (MB) of memory and seven 1-gigabyte hard disks to run the Aloha Club database. The 300-MB Aloha Club database contains 225,000 member records and more than 500,000 dining transactions.

At the time of the Aloha Club system evaluation, Chart House was also making plans to migrate all the company's data from the Honeywell Bull minicomputer to a central server by the end of 1995.

To accommodate the company's mission-critical applications, Chart House needed a powerful and secure relational database management system. "With symmetric multiprocessing support and 32-bit capacity and performance, Microsoft SQL Server provided us with the right combination of power and flexibility," said Townsend.

By the end of 1995, Chart House expects to migrate all the company's accounting and financial data from the Honeywell system to SQL Server. Townsend expects no degradation in server performance. "By taking the approach we did, we didn't have to make a huge investment up front. It's much easier to invest in a $15,000 server than a quarter-million-dollar minicomputer," he said.

Taking advantage of reusable components

After Chart House finalized the decision to build the back end on SQL Server, WinResources chose to develop with the Visual Basic programming system and Microsoft Access. "From the beginning, Chart House realized that having a development tools strategy is very important. It wanted to leverage what it already knew, and it wanted to develop applications across the corporation using a standard set of tools. It also wanted to take advantage of reusable components, including VBX controls and, in the future, OLE Controls," said Karp.

Assigning two full-time developers and one part-timer to the project in April 1994, WinResources identified five major development modules of the new system: new member application entry; restaurant dining transaction entry; posting and exceptions reporting; executive information system; and the customer service desk.

The Frequent Diner Management System.

The first development module entailed distributing new member application entry from its central location to the individual restaurants. Instead of sending membership applications to a single location for data entry, staff at each restaurant now enter the information daily into a local Microsoft Access database. To input the data, the restaurant staff uses a membership application developed in Visual Basic. The application data is then extracted from the Microsoft Access database into a text file, sent by modem to a telecommunications server at Chart House headquarters, and posted to the SQL Server database. Before the data is processed, Microsoft SQL Server performs exception reporting and error checking.

The new procedure eliminated courier costs, reduced the time needed to enter member information, and required almost no training. "The restaurants were already using our Visual Basic menu application, so we were able to leverage what they already knew. That is one of the nice things about Microsoft technology," noted Karp. "We were able to develop an application that looked and acted a lot like the other applications they had on the desktop, thus minimizing training."

To improve the data reliability, magnetic-strip readers now enter dining transactions electronically at the restaurant. Each member has an Aloha Club card that is put through the reader at the time of purchase. Dining transaction data is batch uploaded nightly to a telecommunications server at headquarters before being posted to the SQL Server database. Chart House has virtually eliminated dining transaction errors by using stored procedures to enforce business rules built into the database. For example, the data is checked for transactions under $10, which do not qualify for Aloha Club.

In addition to Veriphone automatic entry, Aloha Club dining credits and other transactions such as gift certificates can be independently posted by customer-service reps.

The third module of the system—a Visual Basic posting routine—was developed for use on both membership and dining transaction data. Data from the telecommunications server is posted to the SQL Server database; during this posting, SQL Server performs exception reporting. In many database systems, exceptions are simply written to a log. By taking advantage of SQL Server's mail-enabled extended stored procedures, WinResources could integrate the exception-reporting system with electronic mail. As Karp explained, "We developed a Visual Basic program that finds transactions of closed accounts, automatically creates a Word customer letter using OLE Automation, merges the account data from the SQL Server database into the letter using mail merge, and automatically sends the letter via Microsoft Mail to the administrator. The letter notifying the customer of his closed account is then immediately sent out. All this with only a few lines of Visual Basic and five lines of WordBasic."

From this screen, customer-service reps can view membership information and respond to members' questions.

Management reporting was another critical component of the new system. Chart House management wanted to track the activity of the program and perform financial analyses. To develop the activity reports, WinResources used Microsoft Access. Because users at Chart House were already familiar with Microsoft Access, they can now modify the existing reports and develop new reports on their own.

To perform the financial analyses, WinResources developed an executive information system in Visual Basic for Applications using Microsoft Excel PivotTable technology, which enables Chart House management to bring in the data from the SQL Server database and examine it from a "bottom-line" perspective. "With the new EIS system, our executives can now effectively assess the financial performance of the Aloha Club Program," Townsend said.

To improve Aloha Club member satisfaction, customer service was completely redesigned. After defining the new parameters, developers created a "customer-service desktop" in Visual Basic. Using standard data-aware controls included with the database engine in Visual Basic, they readily created an easy-to-use front end to the SQL Server database. The new interface allows customer-service representatives to get the data they need in a matter of seconds and respond immediately to member inquiries.

As soon as development was completed, WinResources began the conversion from the minicomputer at the fulfillment house to the in-house SQL Server. According to Townsend, SQL Server's administration tools made the migration relatively painless. The conversion of the 225,000 membership records to the SQL Server database was accomplished in just two days.

Aloha Club increases sales

The new Aloha Club system was fully deployed by early July 1994, two months ahead of schedule; the time needed to deliver membership packets has decreased by 70 percent; and members get answers to their inquires in a few seconds rather than a few days. Member dining transactions are accurate and timely. As a result, members have shown their satisfaction by returning to the restaurant more often. "Using the Microsoft Excel incremental sales PivotTable, we have tracked an eight percent increase in sales thanks to the Aloha Club," said Townsend.

Chart House is also saving money. The fulfillment house fees, courier and fax bills, and costs of correcting data-entry mistakes added up to a hefty sum. Before moving the Aloha Club program in-house, Chart House was spending more than $750,000 a year to maintain the program. The entire new system, including hardware, was developed in less than four months for a cost of $170,000. Maintenance costs are now minimal, and Chart House expects to save approximately $400,000 a year.

Aloha Club is just the beginning for Chart House; technology will play an increasingly important role in the way the company does business. Later this year, Chart House plans to deploy a Windows-based point-of-sale system from Hospitality Systems, and has already installed it in 16 restaurants. By year's end, the firm hopes to move all its accounting data from the Honeywell Bull system to SQL Server. "Our strategic decision to establish the Microsoft family of development tools as our corporate standard continues to fulfill our needs to rapidly deploy scalable, competitive applications," Townsend said.

For more information

For more information about Microsoft products, call the Microsoft Sales Information Center at (800) 426-9400. In Canada, call the Microsoft Canada Customer Support Centre at (800) 563-9048. Outside the 50 United States and Canada, please contact your local Microsoft subsidiary. To contact WinResources, call (619) 689-1200.

Dianne Calvi is president of ITHAKA International, a marketing consulting firm serving high-tech companies. In her spare time, she enjoys skiing, reading, and playing hide-and-seek with her two kids.


Ask Dr. GUI #20

(Remember, he's not a real doctor, although he has a friend who is.)

Created: October 21, 1994

Have a question? Dr. GUI's busy operating schedule won't allow him to answer all questions, but the Good Doctor will answer as many as he can in the next release of the Microsoft Development Library. Send your questions to:

Dr. GUI
Microsoft Developer Network
One Microsoft Way
Redmond, WA 98052-6399

Fax: (206) 936-7329, Attn: Developer Network
Internet: msdn@microsoft.com

Questions in this issue:

SD '94 Memories

Tool Tip Agony: ALT Key Troubles

Setting View Properties with MFC

Eliminate Blinking Cursor, MFC Style

Visual Basic and Child Windows

Verifying Success of Find Method


 SD '94 Memories

From the desk of Dr. GUI

I had the privilege to meet many of you in the member lounge at the SD '94 conference held in Washington, D.C. during the first week of October. I will never forget you folks. How could I? The first character I met was James. James' conference badge indicated his title as "Psych." We talked at length about old technology. When he left he told me to simply put an "o" on the end of his title. Sounds good to me, James. Then there was Peter. Peter is a real doctor at the National Institutes of Health. He became disenchanted with medicine during his internship and turned to kinetic modeling. Sounds a bit like me (although I was never a real doctor and I have never done kinetic modeling!). His favorite disease? Ornithosis, a disease spread by pigeon droppings. I think that he made a wise move out of medicine, don't you? And what about Rusty? A FoxPro nut whose business card bills him as a ski instructor! What was he doing at SD '94? If you ever go to Whitetail, just look for some guy carrying a laptop on the ski lift.

I had fun. I hope all of you did too. I still owe many of you e-mail with follow-ups, so hang in there. Your questions may appear in this column in the future.


 Tool Tip Agony: ALT Key Troubles

Dear Dr. GUI:

I have implemented tool tips in my applications by subclassing the CToolBar class in Visual C++ 1.5 and overriding the OnMouseMove function. When I determine the cursor is positioned over one of the toolbar icons, I pop up a small, topmost window with the tool tip. I then call SetCapture so I will be notified when the mouse cursor is moved off the toolbar. At that time, I remove the tool tip. This all works just fine.

My problem is that SetCapture disables the alt key. If a tool tip is displayed on the screen, the user cannot press alt+f (or any shortcut key that uses alt) to select a menu. What's even worse, Windows will pass a WM_CHAR message with the f key. This sometimes has terrible effects, such as replacing a field in an active dialog box with the letter F.

Do you have a better mouse trap? I'm sure people will beat a path to your door if you do <grin>.

Randy L. Pearson
70573,441
interlink@aol.com

Dr. GUI replies:

Do I have a better mouse trap? No, but this reminds me of a personal goal of mine. I have always wanted to invent something simple and easy to produce. Something like the bottle opener or the thumbtack. It would be so unique that it would be embraced by our culture and sell in the millions. I would retire to some remote island and provide bogus treatments for the imagined ills of the rich and famous.

As luck would have it, I stumbled upon a sample in the Development Library called TOOLTIPS that implements ToolTips for your toolbar under Microsoft Visual C++ version 1.5 and Microsoft Foundation Class Library (MFC) version 2.5. If you take a look at the source file, TOOLBARX.CPP, you will notice that this sample relies upon the use of an undocumented member function (CToolBar::HitTest) of the CToolBar class to implement ToolTips without this nasty problem with the alt key.

Of course, this problem is no problem at all under Visual C++ version 2.0 because the newest release has ToolTips built into the toolbar class. If possible, it would be a very good idea for you to use version 2.0 of Visual C++ (MFC 3.0) so that you can use this built-in feature.


Setting View Properties with MFC

Dear Dr. GUI:

What is the best way to change the background color of a CFormView? I would rather not use OnEraseBackground because the code would execute repeatedly. I would rather register the correct window class background color and pass that to CFormView to use during initialization. How do you initialize the properties of a CFormView?

Don Baechtel

Dr. GUI replies:

Now Don has touched on an insidious subject that afflicts a substantial, but silent (and subsequently Dr. GUI T-shirtless), portion of the Hippocratic faithful. When your CFormView derived object's window is created, you are actually using CreateDialog, rather than the CreateWindow function, to create the window as a child dialog box from the dialog template you designed with App Studio. Because CreateDialog will use only the Windows internal window class, WC_DIALOG, you are forced to accept some unmodifiable window properties, one of which is the background color. A brief foray into the realm of OOP-madness might lead you to try setting the background color with CWinApp::SetDialogBkColor; however, slightly more sane logic would remind you that CFormView is not derived from CDialog and that this method would have no effect on your view's background color. Hmmmm...let's try to trace back to what Windows does when we're not tinkering with the system. That seems easy enough, because Windows just sends a WM_ERASEBKGND message when the window's background needs to be redrawn. Does this mean we write a message handler for WM_ERASEBKGND? Doing so would repaint the background as we want, but how would the background of the controls on the view be redrawn? Once again, the answer lies in how Windows does it. Investigate the default dialog procedure (check the Visual C++ 1.5 DEFPROCS sample in the Development Library for DEFDLG.C) and you will find that WM_ERASEBKGND is dealt with by a call to FillWindow before returning a value of TRUE:

case WM_ERASEBKGND:
   FillWindow(hwnd, hwnd, (HDC) wParam, (HBRUSH) CTLCOLOR_DLG);
   return ((LRESULT) (LONG) TRUE);

If you've skipped ahead and tried to find FillWindow in any of the documentation sources, you will have noticed that it isn't anywhere to be found. Fortunately, Dr. GUI, diviner of all functions obscure and nested, can help demystify this for you. Drum roll, please...it fills a window!! Admittedly, that was a bit anticlimactic, but only because I haven't told you the interesting bit yet. If the HBRUSH parameter with which FillWindow is called is one of a few special values, such as CTLCOLOR_DLG as above, it will send a WM_CTLCOLOR message to the window's parent. This is where we should step in with a message handler in our CFormView derived class. Specifically, we want to create a WM_CTLCOLOR message handler, OnCtlColor, that returns a handle to a brush of the desired background color when it is passed a CTLCOLOR_DLG value.

With the view's background dealt with properly, we need to start thinking about redrawing the controls on our view. Conveniently enough, the other CTLCOLOR_XXX values that accompany WM_CTLCOLOR correspond to the different types of controls, so all we need to do is check for the appropriate values in our OnCtlColor function. Controls that have text attached to them, such as radio buttons and static controls, require an additional processing step to color the background beneath the text. For example, to differentiate text tags with a different color, call CDC::SetBkColor from the appropriate CTLCOLOR_XXX handler inside OnCtlColor. If, on the other hand, you'd like to maintain a consistent background color, use CDC::SetBkMode to change the background mode to TRANSPARENT.

The condensed version of all of this is pretty simple: Set the background color of a CFormView derived object and the controls on it by checking for the appropriate CTLCOLOR_XXX in the OnCtlColor message handler of your CFormView derived class.

Now that we've dealt with the fundamentals, someone has invariably done a bit of exploring and found that CTLCOLOR_LISTBOX and CTLCOLOR_EDIT do not take care of the corresponding components of a combo-box control. A brief review of the WM_CTLCOLOR message will remind you that this message is passed to the parent of the window that needs to be redrawn, which, in our case, is the CFormView derived class for the view's background and "simple" controls. Combo boxes are a bit more complex than their brethren, however, as there are child windows for the edit control and list box components of the combo-box control. Herein lies our problem. When the child windows need to have their backgrounds redrawn, they are sending WM_CTLCOLOR messages to the combo-box control object rather than to the parent's parent, CFormView. The solution is to derive a class from CComboBox to augment its behavior and then attach it to the control object via subclassing. Because this subject is outside the scope of our discussion, I will simply point you to an excellent treatment of the subject by my gifted cohort, Dale Rogerson, titled "Subclassing Windows with the Microsoft Foundation Class Library," which can be found in the Technical Articles section of the Microsoft Development Library. For specific implementation issues, please review the VIEWPROP sample that is included in the January 1995 Development Library. This sample demonstrates everything we have talked about, including how to subclass combo boxes so that you can change their background color.


Eliminate Blinking Cursor, MFC Style

Dear Dr. GUI:

I am using Microsoft Visual C++ 1.0 to develop an image processing application. Basically, I started my work by modifying code from an MFC sample, DIBLOOK. The application has a tool palette. If the user has selected a tool from the palette, the cursor will change to the selected tool shape (such as an eyedropper or magnifying glass) when the cursor is moved into the view. To achieve this, I called SetCursor in CDibView::OnMouseMove. The problem I run into is the cursor blinks between IDC_ARROW and IDC_EYEDROP when the mouse is moved. I suspect this is caused by the system restoring the previous shape of the class cursor of the view. What should I do to change the class cursor of windows created by the framework?

Michael Feng

Dr. GUI replies:

Well, Michael, you correctly guessed that the system is drawing the cursor registered with the window class before drawing yours; this is what is giving you the cursor "blink." Rather than call ::SetCursor from your view's OnMouseMove function, I would suggest overriding the OnSetCursor function in your CView derived class.

By using Spy to watch mouse messages sent to your view object (select Mouse And Input Messages from the Options menu), you will notice that WM_SETCURSOR and WM_MOUSEMOVE are sent in tandem whenever you move the mouse in the window's view. From this information, you can surmise that your code is calling the default implementation of OnSetCursor before you set the cursor again in OnMouseMove. Fortunately this is a pretty easy problem to fix, because you only need to make a message map entry for WM_SETCURSOR, via ClassWizard, and move your ::SetCursor call to the resultant message handler, CViewDerivedClass::OnSetCursor. If you'd like to retain the default cursor shape for child windows, such as the I-bar in edit controls and the arrow for check boxes and buttons, you should return FALSE from this function. To maintain the cursor shape you've set when you move over child windows, return TRUE. There you go!! Flash-free cursors!!

For specific implementation issues, please review the VIEWPROP sample in the January 1995 Development Library.


 Visual Basic and Child Windows

Dear Dr. GUI:

I use MDI in Visual Basic 3.0. In the child window, I do not like the user to close any child window, so I set the property "ControlBox=false" in the child window. It works fine if the child window is not maximized. But, after the child window is maximized, the Restore button is gone. There is no way to restore the child window to normal size. Only cascading or tiling the window enables the Restore button. Is there any way to solve the problem?

K-Yang
khuang@scudc.scu.edu

Dr. GUI replies:

Luckily I didn't take an oath to do this job. So, I can offer you two solutions, one of which is very slippery. In the first solution (here comes the slime), you can turn the MaxButton property to FALSE, which prevents the maximization of the window in the first place! No maximization—no problem (groan, groan!). The second solution gets more to the essence of the problem. Set (and keep) the child window's ControlBox property to TRUE, and bypass the child window's unload process by modifying the child window's Form_Unload function as follows:

Sub Form_Unload (Cancel As Integer)
  If Not gEnd Then Cancel = True: WindowState = 1
End Sub

This has the effect of keeping the window around, so when you maximize it, there is a window to restore. It has not been unloaded, and the Restore button is enabled. The other benefit is that you may minimize the window, and suddenly your application begins to look like a multiple-document interface (MDI) application (duh, probably because it is!).


 Verifying Success of Find Method

Dear Dr. GUI:

I'm not sure if this is one for Dr. GUI, tech support, or whomever, but I would like an answer.

Now that I've done the Paradigm Shuffle (that is, started programming Microsoft Excel macros in Visual Basic for Applications), I've run into a problem: How do I verify that a Find method actually found something? What I would like to do is save the resulting range (cell) in an Object variable, then test to see if it has been set. (This is equivalent to doing a FORMULA.FIND in the old macro language and branching based on the result.) I have not found any way to determine whether the Object variable has been set.

Thanks,

Tom Berube

Dr. GUI replies:

You may wish to check out article Q108892 in the Knowledge Base, but the following code illustrates some other solutions:

Dim ResultCell as Range
Set ResultCell = Range("a:a").Find("GUI")
If ResultCell Is Nothing Then
  MsgBox "GUI not found"
End If

or

On Error Resume Next
Set found = Cells.Find(What:="GUI")
If IsError(found.Address) Then
  MsgBox "GUI not found"
Else
  MsgBox found.Address
End If
On Error Go To 0


Are We Meeting Your Needs?

The Developer Network wants to hear from you. Really.

Nigel Thompson
Technical Writer, Developer Network Technology Group

This is a plea for feedback. We here at the Developer Network hole ourselves up in our offices day after day, researching, writing, editing, rewriting, re-editing articles. But in the midst of this frenzied activity, it's important for us not to lose sight of what you—our readership—want and need.

We'd like to do everything. But, frankly, we can't. There are currently six technical writers in the Developer Network (not counting Dr. GUI, because he mostly just sharpens scalpels and samples medicinal brandy). These courageous half-dozen scribblers arrive at work each day to confront hundreds of function calls in Windows, hundreds of calls in OLE, hundreds of member functions in the Microsoft Foundation Class Library, and hundreds of data structures. On top of that, several versions of Windows are either shipping or under development.

Given this vast sea of potential subject matter (with more being added all the time), what should we write about? In the beginning this was actually an easy decision. We simply picked the most common questions logged by our Product Support Services group. We tried not only to answer the questions but also to show how Windows works internally, and thus hopefully give readers a better understanding of the problems. Because most questions concerned the user interface (and how to get it to look the way you want), one of our writers spent many months writing exclusively on this topic.

As the Developer Network matured (or at least got out of diapers), things changed a bit. The common questions ran out, Windows NT shipped, and Windows 95 (Chicago in a former life) development went full-speed ahead. So our writing team could for the first time explain operating system features and how to use them before a product shipped. Some of us moved to developing under Windows NT and wrote about that experience. One writer spent months inside the Windows NT source code (and its developers' offices) researching a series of articles on how memory is managed in Windows NT and what it means for developers. This was a radical departure from our earlier style, where we were trying to play catch-up with Windows-based programming problems.

Through all this, our team tended to focus on trying to produce well-researched, comprehensive technical articles. We chose this approach because it interests us, and also because we hope these articles serve our audience best. On the other side of the coin, it takes us a lot of work—and time—to produce each article.

Your input is requested

The question is: Is it worth it to you, dear reader? For example, do you feel that you're getting what you want from our technical articles? Are they worth all the time we spend researching them, or would you prefer that we shift our focus and crank out lots of sample applications more in the style of the Windows Software Development Kit (SDK)—lots of code and "neat" features but little or no text to accompany them?

And really that's why we are running this article. We want to hear from you—seriously. We know that you are a busy person, and that your computer is way too old and too slow. And that the fax machine is constantly on the fritz, and that you love e-mail like a poke in the eye with a sharp stick. All that aside, we still want to know what you think. As they say in all elections: "Your vote counts." So here are a few questions that we'd like you to answer. Feel free to make up your own questions if you don't like ours.

1. What areas would you like to see covered?

2. Is it helpful to include documentation for the functions and structures used?

3. Is it helpful to provide an "overview" article and then a follow-up article that goes into more detail?

4. Would you prefer to have samples that are more "functional" (the trade-off being that the sample would be larger, so determining how to do some simple thing would take a bit longer)?

5. What areas have already been covered well enough (and we should therefore quit writing about them)?

6. Is it useful to see articles on beta systems even if you don't have the system or the SDK?

7. We have a lot of C++ articles now. As a C programmer, do they still provide what you want?

8. Do you need to know more about OLE?

9. Do you understand the merits of the different Windows platforms and what it takes to support them?

10. Anything else you can think of.

We really would like to hear from you. We're all having fun here, experimenting and writing articles, but unless you benefit from our efforts what's the point?

You can get in touch with us in several ways:

Internet: msdn@microsoft.com

CompuServe: INTERNET:>msdn@microsoft.com

Fax: (206) 936-7329, Attn: Developer Network

Mail: Microsoft Developer Network, One Microsoft Way, Redmond, WA 98052-5399

It would be helpful if you put "How're we doing?" on the subject head for your correspondence.

Nigel Thompson is a writer in the Developer Network Technology Group and author of Animation Techniques in Win32. He is setting up an advanced snorkeling school in the Cayman Islands.


Deep C: Reusable Code Battle

Brian Overland
Senior Technical Writer, Advanced Technology Division

One of the more evocative adjectives heard around the halls at Microsoft is the word "religious." Coding style as a religious issue. Operating systems as religion. Languages such as C and Pascal, each with their religious followers—and detractors.

In the hallways of software companies, the use of the word "religious" alludes not to a connection to a higher power but to its more specifically human connotations. A "religious" software issue is one that arouses strong emotions, divides people into opposing camps, and defies the power of pure reason to produce a universally accepted resolution.

In C++, one of the more hotly debated subjects these days concerns inheritance. Some of the stronger advocates of the object-oriented programming (OOP) language school invoke the holy words—inheritance, polymorphism, and virtual—with reverence, hoping to usher in the millennium. Meanwhile, devotees of a newer school, that of the Component Object Model, question whether inheritance is the best tool for creating reusable code, and suggest containment and aggregation as superior techniques.

A true appreciation of object-oriented design—with emphasis on the idea of design, not language features—suggests that each technique has its place.

Good design dictates that you structure your system according to the relationships you're trying to model, not through slogans such as "contain, don't inherit" or vice versa.

The Component Object Model (COM) is a binary standard, part of systems architecture at Microsoft and other companies, that extends object capabilities to the system level. I refer to it frequently here because it's the future direction of object orientation. COM supports containment and aggregation (a variation on containment) because of their flexibility. At the same time, COM requires some inheritance relationships.

Code reuse: what's it all about?

What the shouting is all about is the issue of code reuse. Inheritance and containment both do essentially the same thing—they bring a chunk of existing code and data into your own objects.

In essence, it's a simple issue. Consider the real world for a moment. Designing a house could take thousands of years if you had to invent every light bulb, every plumbing fixture, and every material that made up the house.

No one works that way, of course. Every inventor and architect stands on the shoulders of countless others before them, reusing, modifying, and adapting the work and ideas of their predecessors.

A major goal in computer science is to bring this concept of reuse to the writing of software. It's an illusion, however, to think there isn't any reuse now. It's been there for a long time.

Device drivers, for example, are highly reusable code. Every time you read or write to the terminal, you're using the same device-driver routines. The Windows API and operating system functions are reused constantly. Common MS-DOS functions are called billions of times a day all over the world.

The reuse of these functions has nothing to do with how they are written (device drivers are typically written in primitive assembly) and everything to do with how useful they are.

So what about objects?

That said, advances in language features are still important. Structured languages make it easier to write functions and control the scope of data. The use of classes in C++ takes this ability somewhat further, associating the scope of data to an entire set of related functions. As environments become more complex—especially ones that deal with self-contained, graphical objects—this method of program organization is very helpful.

Without the use of an OOP language such as C++, you could only get the same benefits through extensive documentation and self-discipline (which is hard work) or by placing each object in a separate source module (which is not always convenient).

Both approaches require additional work if you want to create multiple instances (or "objects") of the same class. You'd have to allocate a new block of memory each time you wanted another instance.

Now, for inheritance

Once we've established the usefulness of classes and objects, it's easier to see where inheritance and containment come into play. When you create a new class derived from an existing class, you're grabbing some existing chunk of software (code plus data) and adding some features of your own. Anyone else could have written the existing chunk, although you need to understand something about how to use it.

For example, in the following code, my dog gets all the attributes of an animal, and then some:

class CDog : public CAnimal

{

int breed;

CString name;

} mydog;

In this simple case, the results are essentially the same as the following example of containment:

class CDog

{

CAnimal animal;

int breed;

CString name;

} mydog;

What's the difference? Only a minor one, actually. In the first case, all of CAnimal's public members become members of the object mydog. In the second, you access the same members through a member variable, animal:

mydog.animal.weight = 100;

(Protected members create a true difference between the two cases, but let's ignore that difference for now.)

Pros of inheritance

In C++, inheritance does have an exclusive role: It is required for the creation and exploitation of virtual functions. This aspect of inheritance is natural, for it imposes discipline on what would otherwise be chaotic, free-wheeling late binding of functions. C++ forces you to be deliberate about virtual functions by saying, "All these classes are variations on the same base class, and they all implement the function F() in the base class."

What's really going on is that when you declare a base class with a virtual function, you're leaving the field open for a whole range of child classes, each with their own implementation of that function. New types of objects can be added later with as-yet-unwritten implementations, and client code need not be recompiled.

You can do all of this in C with callback functions and function tables. But in C++ the process is easier and more systematic.

Even in the Component Object Model, inheritance is necessary. In this model, you must be able to query each interface, as well as reference and release it, so each and every interface must implement functions inherited from IUnknown.

Pros of containment

Although inheritance is more powerful in terms of functions, it is less flexible, because you can inherit from a base class only once. Suppose you want to make multiple use of an existing class. For example, my dog has four legs:

class CDog

{

CLeg left_front, right_front;

CLeg left_rear, right_rear;

int breed;

CString name;

} mydog;

You couldn't inherit from CLeg and thereby get four copies of CLeg objects—at least not directly.

Another issue concerns multiple inheritance. If you want each instance of my class to get all the material in two existing classes (say, CLeg and CTail), you could only inherit from both by using multiple inheritance. This kind of inheritance raises some messy issues, not the least of which is that it is extremely difficult to implement in C when virtual functions are added. (This is an issue in the Component Object Model, which creates a binary standard extensible to C.)

Containment/inheritance harmony

Both approaches have distinct advantages. It's a mistake, however, to think that one is basically more efficient or easier to use than the other in all cases. You've probably heard claims that the proper use of inheritance requires access to source code and that you don't always know what you're getting. Yet this is equally true of containment. In either case, it helps to know what you're bringing in, and you might not know without adequate documentation.

Ultimately, the point of view that emphasizes modeling principles, and the role of inheritance and containment in both, is well taken. To return to our first example, CDog really should inherit from CAnimal after all, because dog has a "kind of" relationship to animal. At the same time, dog "is made up of" legs. A little common sense tells us that the relationships in the model provide the key to the most suitable design.

class CDog : public CAnimal

{

Cleg left_front, right_front;

Cleg left_rear, right_rear;

int breed;

CString name;

} mydog;

Brian Overland, a published author, sometime programmer, and veteran of several Microsoft languages groups, now works in interactive television. He fights inheritance wars there every day.


Desktop Developers Get Client-Server Boost

Workstation System offers same functionality and tools as SQL Server

The recently released Microsoft SQL Server Workstation System version 4.21 is designed to make it easier for Windows desktop developers to take advantage of the rapidly growing client-server marketplace.

The SQL Server Workstation System combines the Microsoft SQL Server client-server database management system with the SQL Server Programmer's Toolkit. The system offers the same functionality, tools, and performance as the multiuser version of SQL Server and is intended to deliver the tools needed to build sophisticated, high-performance client-server systems, including ones compatible with Microsoft BackOffice. "We've tried to make it attractive to first-time client-server developers by including both engine and development tools in a single, low-cost package," said Daniel Small, a product manager in the Microsoft business systems division.

The Workstation System runs on Windows NT Workstation and Windows NT Server platforms. It is licensed for a single user—in a development or full production environment—and permits up to 15 simultaneous network database connections.

Advanced programmability features

Developers experienced with desktop databases can now take advantage of SQL Server's advanced programmability features, such as triggers and stored procedures. For example, the extended stored procedure (XP) "opens" the engine's architecture and makes SQL Server a more flexible development platform. XPs are user-defined functions written as Windows NT dynamic-link library (DLL) routines. They allow custom functions to be added to the server—functions that behave as though they are native.

The power of extended procedures can be seen with xp_sendmail, an extended function included with the Workstation System that sends messages to an e-mail recipient when a change in the database occurs. It's useful for developing just-in-time inventory systems or other work-flow applications.

The SQL Server Workstation System gives developers access to the full range of capabilities of the BackOffice client-server architecture. BackOffice includes a set of server-based applications that provide an integrated platform for business computing. The server-based applications include SQL Server, Microsoft SNA Server, Microsoft Systems Management Server, and Microsoft Mail Server. By supporting industry-standard interfaces such as DB-Library and open database connectivity (ODBC), developers can build applications for a wide range of platforms, including Windows NT, Windows, MS-DOS, OS/2, and the Macintosh. In addition, C, C++, and Visual Basic languages are supported.

The Workstation System also comes with the Open Data Services (ODS) programmable gateway, which enables developers to create server-based gateways to host data sources, audit and security systems, and other sophisticated server-based applications.

An upsizing platform for developers

The SQL Server Workstation System supports all of Microsoft's professional development tools, including Microsoft Access, FoxPro, Visual Basic, and Visual C++.

SQL Server can be used with the Microsoft Access Upsizing Tools (available in the January Development Library) to develop applications that migrate easily from the desktop to the enterprise when multiprocessor performance, security, or transaction integrity is needed.

One result of Microsoft's extensive database management system kernel re-engineering effort is that SQL Server—including the Workstation System—"is able to deliver a level of performance available previously only from mainframe-class computers, at a fraction of the cost," Small said.

Support for a broad range of networks

The SQL Server Workstation System features a network-independent design with integrated support for all popular local area network (LAN) environments. Support for Microsoft Windows NT and LAN Manager, Novell NetWare, IBM LAN Server, Digital Pathworks, Banyan VINES, and AppleTalk, and for TCP/IP-based networks using native protocols (TCP/IP, IPX/SPX, DECnet, ADSP, NetBEUI, and named pipes), is also provided.

SQL Server supports all these protocols simultaneously, allowing you to deploy solutions in heterogeneous LAN environments common in today's large corporations without requiring multiple network protocols at the client.

Together with BackOffice components, the Workstation System can also serve as a useful platform for value-added resellers (VARs) seeking a platform on which to build their next generation of turnkey solutions. Its relatively low cost and full functionality make it widely applicable for networked and stand-alone applications, such as remote or branch office automation systems.

SQL Server works with hundreds of leading tools and applications. More than 200 independent software vendors offer applications and industry-specific solutions based on Microsoft SQL Server, and more than 1200 Microsoft Solution Providers worldwide offer in-depth consulting, training, systems integration, and technical support. All of these products and services support the new Workstation System.

The SQL Server Workstation System has an estimated retail price of US$499. Customers who already own the earlier SQL Server Desktop System can upgrade for around US$149. See your Microsoft reseller for additional information.


Developer Network OffRamp Debuts on Internet

Aim is to provide a greater quantity of timely information

Andrew Himes
Group Manager, Developer Network

The folks who bring you the Developer Network News, the Development Library, and the Development Platform have inaugurated a new information service on the World Wide Web (a graphical information-browsing system on the Internet): the Developer Network OffRamp.

We've been working on this plan for some time now. Developers have been telling us that they want more timely information from Microsoft, and they want us to make full use of the capabilities of the Internet for communicating and publishing. Our response is the OffRamp, your place to get via the Web the most up-to-date news and technical strategy information from Microsoft.

You can access the Developer Network OffRamp via Microsoft's World Wide Web server at http://www.microsoft.com. Once on the Microsoft Home Page, click the Developer Network OffRamp button.

The OffRamp includes three major areas:

• Developer Network News, an online version of our newspaper, updated weekly. (See Taking the Developer Network News Online.)

• Fast Track, a source of technical and strategic information, updated every two weeks.

• Developer Network membership information.

Timeliness and flexibility on the Internet

Publishing on the Internet provides us with several major benefits compared to print- or CD-based publishing. For one thing, we don't have the same space constraints. The paper edition of our newspaper that you are now reading is limited to 16 pages, and it's a challenge each month for us to fit the most essential and interesting articles into the newspaper. We invariably are forced to cut or postpone printing several articles. On the Web, however, we are limited only by disk space (which is relatively cheap) and the work it takes to make quantities of information easily usable and navigable.

Timeliness is an important factor in publishing, and the Web will help us get the right information to you in a much shorter period of time. Our publishing schedules for the Development Library on CD (every three months) and the Developer Network News on paper (every two months) are lengthy by comparison with our publishing schedule for the Web.

We continually update material on the OffRamp and add new content, so you can be sure that whatever is there is timely and appropriate. Each item is dated, so you know exactly when we added it to the OffRamp. In addition, all of the most important new material on the OffRamp is also included in the next available release of the Development Library on CD.

To obtain the Development Library, sign up for a Level 1 membership in the Developer Network. A one-year subscription to Level 1 costs US$195 ($275 CAN), which buys you four quarterly releases of the Library CD-ROM, chock full of technical information, plus six issues of the Developer Network News.

A Level 2 membership delivers all the benefits of Level 1, plus four quarterly releases of the Development Platform, which contains Microsoft API-level software development and device driver kits and the currently released versions (both U.S. and international) of the Windows and Windows NT Workstation operating systems for development and testing purposes. A one-year Level 2 membership costs US$495 ($695 CAN).

To join the Developer Network, call (800) 759-5474. Outside the United States and Canada, call the local Microsoft subsidiary.

Andrew Himes shares his lunch with a 47-inch-long green lizard named Igweena Athena Iguana, who is getting bigger by the minute.

Additional Information

Developer Network information

The Developer Network information area on the OffRamp provides up-to-date membership news and is designed to answer questions such as the following:

• How do I join the Developer Network?

• What content will be added to the next release of the Development Library?

• What new operating systems or toolkits will appear on the next Development Platform release?

• How do I change the membership options I've selected?

• What are the licensing restrictions for the Development Library and Development Platform?

Taking the Developer Network News online

The Developer Network's Web-based newspaper contains all the content of the paper-based version, plus a lot more. You can see all the news articles, columns, and features from past printed versions (including the most recent one), and in the "Extra" section you can also see new content added each week, news stories, features, and new technical columns, even before they appear in the printed newspaper.

Developer Network Fast Track

The Fast Track area contains technical and strategic information, including selected technical specifications, white papers, backgrounders, conference papers, selected samples and tools, information about developer tools and products from Microsoft, and the Microsoft Developer Knowledge Base.

Note: The Fast Track area is only a sampling of the much larger universe of content on the Development Library CD.


The Human Factor: With Windows 95, You're Never out of Control(s)

Tandy Trower
Director of User Interface Design

In this column, I'll continue my coverage of the Windows 95 (formerly Chicago) user interface by taking a look at some of its new controls and providing some advice on their use. Most of these are the very controls the system uses.

Toolbars made easy

The new toolbar control includes the attributes found in most toolbars. Not only can you populate a toolbar control with other controls, but ToolTips are also automatically supported for those controls. (More on ToolTips in the next section.) In addition, the control handles wrapping of controls if the toolbar is resized. It even supports the ability to undock the toolbar from the edge of a pane or window and display it as a palette window, or dock it against another edge or window.

If you provide toolbars in your application, consider them a nonrequired part of the basic interface, configured with common, frequent functions. Remember that they do steal screen real estate, so allow a user to turn your toolbars off (usually via a command on the View menu). Also, consider allowing users to customize what they want on the toolbar. The system-supplied toolbar control even supplies an interface for this.

Tips are encouraged

It has always been difficult to choose whether to use text or graphics or both for buttons on a toolbar. Usually graphics are the best alternative because, if designed appropriately, they are more compact and can transcend international language barriers without translation. However, until users learn them, they may be too cryptic to be of much use—thus the temptation to include a textual label. This, however, makes the button larger and somewhat defeats the purpose of using graphics in the first place.

ToolTips to the rescue! A ToolTip is a small, pop-up window that displays a textual label for the control. Because they come up after a short time-out (which is user-adjustable), they don't take up permanent screen real estate and don't interfere with the interaction of more experienced users who recognize what the graphic represents.

Don't limit your use of ToolTips to buttons in a toolbar. Any control without a label may be able to benefit from a ToolTip. They may even be useful with a scroll bar to indicate the current page number as a user drags the scroll box.

What's my status?

Status bars are another common interface element. These are handy not only for providing state information within a window, but are also useful for giving brief, descriptive information for menus and controls as a user moves over them. Windows 95 makes it easier to include a status bar by providing one as a standard control.

And speaking of status, the system also provides another new control called a progress indicator. This is a graphic bar that fills in, thus providing feedback to a user about the completion status of a process. Progress indicators can be used in message boxes or status bars. For a multipart process, they should always be used to indicate the progression of the entire task or process, unless each part is clearly labeled.

It's a slider!

When you want a control that allows a user to change a value that moves along a single dimension, such as controlling brightness or volume, you have generally been left to use a scroll bar. This isn't the best idea, since scroll bars were designed for scrolling. Now Windows 95 provides a handy new slider control that looks a lot like the controls used on audio or video equipment for similar control.

Spinning wheel

The user interface (UI) guide for Windows 3.x (The Windows Interface: An Application Design Guide) discusses a control called a spin box. This control is a text box with a pair of buttons used to add or subtract the value from a preset range of possible values. The values wrap; for example, on a 0 to 9 set of integers, after 9 you get to 0. These usually wrap around at the top or bottom of the set of values, giving the effect of a spinner or wheel. Think of a roulette wheel (only with sequential numbers) or one of the wheels in your car's odometer.

Windows 95 makes creating that control easier by including a special control, called the up-down control, that provides the increment and decrement buttons. It operates like a simplified form of a scroll bar.

A tree grows in Windows 95

The new tree view control allows you to organize a list of hierarchically related items. In fact, it is the control that the Windows Explorer in Windows 95 uses to display an outline of folders.

But you need not limit it to the presentation of file hierarchies. The control allows you to include text and graphics and, optionally, button controls for expanding and collapsing the outline.

Makin' a list

The list view control allows items to be listed in large icon, small icon, phone directory-style column, or multiple-column report view. Like the tree view control, this control is the same one that the system uses to display icons in a folder. It can come in handy when you are creating your own container of iconic objects. It also provides support for drag and drop.

One from column A...

The new column heading control allows you to create column headings for a list of objects. You can define the number of columns, the labels for each column title, and the sorting of entries in the list based on a particular column.

Rich text?

Would you like to have the kind of text formatting capabilities found in Microsoft Word? With the new rich-text control you get multiple font support for text within the control, rather than just a single font setting for the entire control. You also have basic paragraph formatting properties, such as alignment, tabs, indents, and bulleting. The control even supports OLE.

Because the control supports most of the messages of a standard text box, it can easily replace your existing text controls. You do have to provide the user interface elements for formatting font or paragraph properties.

Tabs, property sheets, and blankets

Actually, there isn't a blanket control, but Windows 95 does make those nifty notebook-like tabs available to you, either as a set of tabs or as a complete property sheet with all the trimmings. You can define your tabs to include text, graphics, or both. When laying out secondary windows with these controls, make certain you place your command buttons appropriately.

Buttons on a tabbed page should apply to that page. Buttons placed outside a tabbed page (but within that window) should apply to the entire window. For example, if an Apply button only applies the changes on one particular page, it should be on that page. However, if you allow the user to apply changes on different pages as one operation, the button should be placed outside the page.

Other goodies

There isn't room in this column to cover all the new controls. I could have mentioned pen controls, such as boxed edit and ink edit; or the shortcut key control, a way of allowing the user to enter a key combination that can be assigned as a shortcut key. Add to this the fact that the common dialog boxes have been modified for the Windows 95 visual style (Open and Save As even provide support for long filenames) and you have quite a bundle of new support to make writing your Windows 95-based application easier.

More information about how and when to use these controls can be found in the Win32 Programmer's Reference and in the draft of the Windows 95 User Interface Design Guide. Also, check out Nancy Cluts' articles on implementing common controls in Windows 95 in the January release of the Developer Network Development Library.

Tandy Trower is the director of UI design at Microsoft. While often considered the Roger Ebert (or is that Gene Siskel?) of Microsoft's product UI, he flatly denies that he is Dr. GUI's older brother.


Industrial Strength OLE: Using Microsoft's Object Technology to Build Business Solutions

Charlie Kindel
Program Manager, Developer Relations Group

OLE Industry Solutions is the term Microsoft uses to describe its efforts on behalf of a series of industry-specific initiatives to help groups of software vendors, solution providers, and customers in varied industries and vertical markets develop and market OLE-based standards.

There is no formal process involved in OLE Industry Solutions, but each initiative shares the same goal—to gain widespread adoption of OLE-based standards that solve business problems. These standards can be built on top of existing Microsoft-defined interfaces, or they can be entirely new interfaces designed to meet specific business needs. In either case, the interfaces are specified using the rules set forth by the OLE Component Object Model.

The evolution of OLE

In 1991 Microsoft released OLE 1.0, the first widely adopted specification for developing compound-document applications. A compound document is one that contains multiple data types, such as text, graphics, and video.

This was followed in early 1993 by the release of OLE 2.0, which provided a much richer compound-document model as well as OLE Automation (which permits applications to expose command sets that operate within and across applications), OLE Drag and Drop (which allows objects to be dragged from one application and dropped into another), and generic services (which are applicable across almost any problem domain).

At the core of OLE 2.0 is the Component Object Model (COM), a specification that allows developers to design interfaces that enable interaction among components. In fact, OLE 2.0 is simply a set of COM interfaces designed by Microsoft.

OLE interfaces

The interfaces defined in the OLE 2.0 specification can be generally categorized as follows:

• OLE generic services. These interfaces are truly generic in nature and can be used in almost any problem domain. Examples include the uniform data transfer interfaces (IDataObject and IAdviseSink), memory management interfaces (IMalloc), and storage interfaces (IStorage and IStream).

• OLE Documents. The OLE 2.0 specification contains about a dozen interfaces that deal specifically with compound documents. These interfaces typically have names starting with IOle; for example, IOleObject, IOleWindow, IOleInPlaceSite, and so on.

• OLE Automation. The OLE 2.0 specification defines a set of six interfaces that together make up OLE Automation: IDispatch, ITypeInfo, ITypeLib, IEnumVARIANT, ICreateTypeInfo, and ICreateTypeLib.

Microsoft followed up OLE 2.0 by releasing in October 1994 the OLE Controls specification, which defines the COM interfaces used by OLE Controls (for example, IOleControl). The OLE Controls specification also defined some new "generic" interfaces that are used by OLE Controls but are useful in other contexts as well. These include IConnectionPoint and IConnectionPointContainer.

Microsoft will continue to expand OLE by defining additional COM interfaces. For example, the current OLE 2.0 specification for compound documents does not specify interfaces that would allow embeddings to span multiple pages. Microsoft intends to address this shortcoming in the not-too-distant future by defining new COM interfaces.

Finding "safe" ground for standards

Anybody can extend OLE by defining COM interfaces; in fact, many independent software vendors (ISVs) have defined their own COM interfaces for use within their applications. The procedure for defining and using new COM interfaces is fully documented in the OLE 2.0 Software Development Kit, which is available in the Developer Network Development Library.

The difficult part is getting other companies to use the new interfaces. To understand why, look at the computer game market. Imagine that an enterprising software company, XYZ, designs a set of COM interfaces that define the interactions between arbitrary "game boards" and "game pieces" so that users can build their own games.

How does XYZ get other game software companies to write game boards and game pieces? The software game industry is pretty competitive, and it's not at all clear that any two companies are willing to cooperate. In addition, XYZ may have missed a design point important to another class of game. What is needed is a neutral party that can provide a safe meeting place and allow these companies to get together to develop industry standards. Microsoft hopes that its OLE Industry Solutions can serve as a way to bring all those concerned together to agree on standards.

What is an "industry"?

The term "industry" is used here to describe any community of software vendors, solution providers, or customers concerned with a common set of business problems. Some of these communities are defined by the vendors who develop products to solve specific, or "vertical," problems. Examples of vertical markets include:

• The market data industry. This is the community of companies within the capital markets sector of the financial services industry that produce and consume market data. For example, firms such as Reuters sell market data that is delivered, via software, in real time to brokerage houses, banks, and individual investors.

• The engineering design industry. This industry includes companies such as Intergraph, Autodesk, and Cadance, which sell 3-D computer-aided design (3-D CAD) modeling and other technical applications.

Other communities, such as insurance companies and retail bankers, are defined not by their solution vendors but by their customers. Currently a group of life insurance ISVs is working on an OLE-based standard to reduce manual processes and provide interapplication communication for the life insurance sales and marketing desktop. (See "OLE for Life Insurance Aims at Integration.")

A group of leading suppliers to the retail banking industry, known as the Banking Solutions Vendor Council, has developed an API standard for accessing banking-specific devices from Windows-based applications. This group is now investigating the encapsulation of this specification in standard OLE interfaces.

Microsoft's role

Each industry and vertical market has different needs, politics, and problems. In some industries an existing standards body is interested in defining standards based on OLE. In this case Microsoft will provide technical information and marketing support to that standards body. An example of this is the work going on in one of the special-interest groups within the healthcare industry's HL7 standards body. HL7 is a standards-setting organization for healthcare information systems. (See "OLE industry solutions listings" in the "Additional Information" section at the end of this article.)

In other industries no standards group exists, but there are highly motivated vendors and customers interested in forming such a body. In this case Microsoft would work to provide meeting facilities on "neutral turf" to get all the interested parties together. The Open Market Data Council for Windows, which defined the WOSA/XRT standard, is an example of this kind of approach. (See "OLE for Real-Time Market Data resources" in the "Additional Information" section at the end of this article.)

In the engineering industry, several companies that are early adopters of OLE technology are taking the initiative to define a set of COM interfaces for 3-D CAD and other engineering applications. These companies are willing to put this specification in the public domain in the hope that the power of such a standard will be so compelling that other vendors in the industry will adopt them as well. Microsoft will hold design reviews of this technology, allowing all companies interested to provide input into the design. Microsoft will help these vendors to publish this extension to OLE, to hold developer conferences, and to distribute sample code and documentation widely.

The listings in "Additional Information" (below) show which OLE Industry Solutions currently exist, their status, and where to get more information. If you are involved in an industry or vertical market not represented here, and you are interested in getting an OLE Industry Solutions started or want to be put in touch with others in your industry, send e-mail to i-stds@microsoft.com.

Charlie Kindel is program manager for OLE Industry Solutions in the Microsoft Developer Relations Group. He also wears the hats of software design engineer and technical evangelist.

Additional Information

OLE for Real-Time Market Data (WOSA/XRT) resources

Windows Open Services Architecture (WOSA) is a set of technologies for streamlining access to services and data on the Windows platform. WOSA/XRT, or WOSA Extensions for Real-Time Market Data, is just one of many components that fall under the WOSA umbrella.

The WOSA/XRT standard is based on OLE. The standard was defined by the Open Market Data Council for Windows (OMDC), an organization of more than 75 independent software vendors, solution providers, data vendors, and customers from the capital markets sector of the financial services industry. WOSA/XRT is currently the only WOSA standard based completely on OLE.

WOSA/XRT was the first of the OLE Industry Solutions and thus serves as a model for other OLE Industry Solutions. However, WOSA/XRT is also different from all other OLE Industry Solutions because it is the only such solution that is part of WOSA.

WOSA/XRT technical resources

In February 1994, the OMDC released version 1.0 of the WOSA/XRT Design Specification. In March 1994, Microsoft held a developers' conference and made available a set of WOSA/XRT technical articles and sample code. In October, version 1.01 of the WOSA/XRT Specification was released, and articles and samples were updated to reflect the new specification. The specification, articles, and samples are available in the January 1995 release of the Developer Network Development Library. Below are brief descriptions of the articles and samples.

"WOSA/XRT Solutions Implementor's Guide." Intended for anyone building systems using WOSA/XRT objects, this article is designed to provide the necessary background for end users to incorporate WOSA/XRT-compliant objects into their everyday work.

"XRTXL5: Real-Time Extensions for Microsoft Excel." This article provides detailed information on how to use a Microsoft Excel 5.0 add-in module from the perspective of end users as well as developers using Visual Basic for Applications. Microsoft has also developed an AddIn sample that enhances the ability of Microsoft Excel to interact with WOSA/XRT data objects. While the Microsoft Excel 5.0 OLE support works fine with WOSA/XRT data objects, AddIn provides for additional performance, robustness, and ease of use.

The following technical articles in the Development Library, although generalized to OLE, were originally written to help WOSA/XRT developers: "Implementing OLE Automation Collections," "Local vs. InProc Objects in OLE," and "OLE Component Design Issues." Please note that any article related to OLE is also relevant to WOSA/XRT.

WOSA/XRT-related sample code is also available in the Development Library in the Sample Code/Technical Article Samples/OLE Samples/WOSA-XRT Samples bin.

OLE industry solutions listing

Below is a list of the efforts that we do know about, and information on becoming involved with each one. Note: It is possible that there are OLE solutions that Microsoft is not aware of.

OLE for Real-Time Market Data (WOSA/XRT)

WOSA/XRT stands for Windows Open Services Architecture/Extensions for Real-Time Market Data. (See the "OLE for Real-Time Market Data (WOSA/XRT) resources" section (above) for more information.)

Industry group:

Open Market Data Council for Windows (OMDC)

Contact:

wosaxrt@microsoft.com

Specification:

• Current version is 1.01.

• Internet: ftp.microsoft.com

• Filename: /developr/drg/OLE-Info/OLE-Industry-Solutions/WOSA-XRT/XRTSPC.ZIP

• CompuServe Information Service: Library 4 of the WINEXT forum.

• Filename: XRTSPC.ZIP

• Or see the January 1995 release of the Microsoft Development Library. Search for "WOSA/XRT".

OLE for Healthcare Systems

Industry group:

HL7 (Health Level 7). A widely accepted standards body of healthcare providers and healthcare information systems vendors.

Contact:

• i-stds@microsoft.com

• Internet: ftp:dumccss.mc.duke.edu

• Filename: /standards/HL7/sigs/SIGOBT

OLE for Process Control, Engineering, and Manufacturing

Industry group:

WinSEM

Contact:

Subscribe to the WinSEM mail list by sending a message to listserv@labtech.com. Include in the message body the text "subscribe winsem name" where name is your name.

OLE for Life Insurance Systems

Industry group:

SLIEC (Solutions for Life Insurance Enterprise Computing). A group consisting of Andersen Consulting, FDP, E-Z Data, Sterling Wentworth, Lincoln National, and Microsoft.

Contact:

i-stds@microsoft.com


International Language Glossaries Now in the Development Library

If you're looking for just the right word in a non-English language to describe a product feature or procedure, the Developer Network Development Library has a helpful resource for you.

To promote the use of common terminology in the international developer and localization communities, Microsoft is making its international language glossaries available in the Development Library. The January release will contain glossaries of released products in German, French, Spanish, Brazilian Portuguese, Italian, Dutch, Danish, Swedish, Norwegian, Finnish, Russian, Czech, Hungarian, Polish, Turkish, and Greek. The plan is to add three Far Eastern languages in the spring.

Not all product glossaries are available in all languages, but you will find most major Microsoft products represented in this collection. The glossary collection will be updated with each release of the Library.

Microsoft is making this terminology available for individual use of specific terms in software development and localization. A separate license must be obtained from Microsoft for any other use. If you have questions about the glossary collection, please write to Ursula Schwalbach, Terminologist, International Quality Assurance Department, One Microsoft Way, 3/2, Redmond, WA 98052, or call (425) 936-1526.


International Mobilization for Windows 95

30 different language versions to ship within six months of release

Ken Fowles
Manager, Developer Relations Group's Globalization Team

January 9, 1995

Within six months of the release of Windows 95 (formerly known as Chicago), 30 different language editions are scheduled to ship. (See Table 1 for specific time frames.) This will have an impact on all applications, since a new standard is being set for international availability of the Windows platform.

How does Microsoft manage code on a worldwide project of this scale? What are the main things Microsoft is doing to avoid going crazy trying to release so many language editions in a reasonable amount of time? More importantly, what can Developer Network-equipped developers learn from this experience?

Table 1: International Windows 95 ship time frames.

Brazilian Portuguese, Dutch, English, French, German, Italian, Spanish, Swedish

0-3 weeks

Danish, Finnish, Iberian Portuguese, Norwegian

2 months

Japanese, Japanese (NEC 9800), Korean, Traditional Chinese

3 months

Basque, Catalan, Czech, Greek, Hungarian, Indonesian, Polish, Russian, Simplified Chinese, Slovenian, Thai, Turkish

4 months

Arabic, Hebrew

6 months

30 languages, only three code bases

Microsoft is saving a lot of time by developing just three separate code bases: SBCS (single-byte), DBCS (double-byte or multibyte) and Mideast (bidirectional). These three cover 30 languages. For example, Microsoft isn't building just an English-language version of Windows 95. Rather, it's building a single-byte version that happens to have an English user interface (UI) but can be easily transformed into German or French through "no-compile" techniques of exchanging Win32 resources.

If you want to see no-compile Win32 resource editing and many other Windows 95 internationalization issues covered in technical detail, the Microsoft Developer Relations Group will hold a one-day Win32 globalization seminar in 14 cities during February. The cost is approximately US$150. To register, call (800) 619-7689 or (415) 979-2288, or fax (415) 979-2270.

The efficiency gains are substantial, since Microsoft no longer has to spend an additional minute (or year) ripping apart existing code to create another language edition. Simultaneous shipping in several languages becomes practical, instead of merely theoretical. This also improves quality, because the sources remain unchanged and only the localized portions of the UI require testing. In addition, bug fixes affect all localized versions automatically, since builds are based on a common binary.

New emerging markets can be added to the list at any time—for example, the SBCS version can be localized into Klingon with no additional technical work. Unfortunately for Trekkers, there is currently not enough interstellar commerce to justify a Klingon edition of Windows 95. (If there were a Klingon edition it probably would look like Figure 1.) If someone could make a compelling case for it, Microsoft might consider adding it to the list.

Figure 1: Klingon language edition of Windows 95 (not currently scheduled).

Why stop at three code bases?

But why limit the streamlining to three code bases? Isn't one worldwide (or even one interplanetary) code base the ultimate goal? What about that thingamajig called Unicode, wasn't it supposed to handle this all automatically?

Well, not exactly. Internationalization means a heck of a lot more than what code page you pick, or using a universal language-independent code page (that is, Unicode).

Remember the fundamental design goals of Windows 95—while it gets a bunch of new cool stuff, it also has to be as small as possible, be very fast, run on the majority of today's hardware, and not break too many existing apps.

Microsoft took a hard look at this and came up with three language-region families required for Windows 95. The DBCS editions, which ship to the Far East, include some code that really doesn't need to be shipped elsewhere, such as an IME (input method editor) for complex writing systems, an EUDC (end-user defined character) editor, and all the code for passing DBCS (mixture of 8-bit or 16-bit) characters through the UI, as well as a bunch of applications in the Far East region that require DBCS support.

The editions for the Middle East support both left-to-right and right-to-left UI text placement, and special ligature and text justification (Kashida) handling—an absolute requirement for that region, but not elsewhere.

Thus, if Microsoft had one worldwide binary, we would have saved a few additional steps, but at the unacceptable expense of shipping a larger product at a much later time. What we have instead are three well-optimized source trees that cover 30 languages, all tested and developed by one team.

Responding quickly

The most successful companies will be those that can quickly respond to emerging growth opportunities anywhere in the world. So, Microsoft encourages any application developer (that means you) at a minimum to set up projects so they can be localized through no-compile Win32 resource-file editing. If you need to optimize for size (as many of us do), consider managing your projects as three major language regions like Microsoft did, but within each region stick to only one code base. You will find this approach easiest if you are targeting Windows 95.

If you have the type of project that can afford more size, it is entirely possible to ship one binary with worldwide functionality that will run across all language editions of Windows 95, and on Windows NT. An example of this is the English version of Visual C++ 2.0, which is DBCS-enabled. If you run Visual C++ on Japanese Windows, you can add Kanji literals and comments to your source files.

Want to know more? Read the International Handbook for Software Design, which is in the Developer Network Development Library. Nadine Kano of Microsoft's Developer Relations Group is also currently rewriting the handbook. Her book is scheduled to be published this spring by Microsoft Press.

Another resource is the Globalization Resource Kit (GRK), a CD-ROM with basic technical and marketing information plus a directory of third-party vendors who can provide internationalization-related services. If you don't have one, send e-mail with your mailing address to global@microsoft.com and ask for a GRK. Also, if you want to get Windows 95 internationalization information that will be published in the future, join the Developer Network, which will release information when it becomes publicly available.

Ken Fowles manages the Microsoft Developer Relations Group's globalization team. His distractions include playing the violin, rebuilding his house, and riding his Harley to biker events in Sturgis, South Dakota.


OLE for Life Insurance Aims at Integration

Joe Long
Technical Evangelist, Developer Relations Group

The insurance industry can be divided into three main categories: life, health, and property and casualty. In the property and casualty industry, a number of vendors provide solutions that completely automate the agency. Life insurance, however, has no true counterpart to these systems, so life insurance firms must purchase solutions from multiple vendors, and then pay the vendors or consultants to integrate the applications.

This usually means modifying the applications to share information using a flat file transfer. This "one off" consulting is expensive, so life insurance companies typically don't buy a lot of software, nor do they upgrade existing software much. Integration is also minimal—each application typically has its own database and data entry screens. It is unusual, without manual intervention, to have changes in one database reflected in another.

OLE for Life Insurance is designed to be a first step toward integrating these systems. OLE for Life Insurance is being created by an industry group called Solutions for Life Insurance Enterprise Computing (SLIEC), which consists of Microsoft, Andersen Consulting, FDP, E-Z Data, Lincoln National, and Sterling Wentworth.

OLE for Life Insurance is a protocol for an OLE control. Like WOSA/XRT (see "OLE for Real-Time Market Data Resources"), OLE for Life Insurance defines no new interfaces. Instead, it relies on OLE Automation, uniform data transfer, and OLE events.

It works by providing an OLE interface (using OLE Automation collections) to a common logical database to store "common" information. This information initially pertains to clients or customers; for example, addresses, telephone numbers, or risks such as skydiving, race-car driving, smoking, and so on.

A typical application that is written to use OLE for Life Insurance will use OLE Automation to get access to this common data. The OLE control keeps a pointer to the object in the running object table, which is a list of globally available objects, so that each application that accesses data uses the same object.

This enables the object to "watch" what information is being accessed, modified, or deleted. Each application that is using the OLE control is notified of any change to the data. Using this allows applications to obtain all important information pertinent to a particular client, such as whether a different application is currently working on that client's record. In other words, by using the running object table, interapplication communication becomes an integral part of the architecture.

Joe Long is the technical evangelist in Microsoft's Developer Relations Group responsible for financial services and insurance.


OpenGL: Windows NT Gets 3-D Graphics Library

Dale Rogerson
Technical Writer, Developer Network Technology Group

Until recently, fast, high-quality, 3-D graphics like those produced for the movie Jurassic Park could only be built on an expensive platform such as Silicon Graphics' IRIS workstation. This meant that the quality of graphical animation that could be produced on less expensive, Windows-based PCs suffered greatly by comparison.

However, Windows NT version 3.5 and the Win32 API now include OpenGL, a 3-D graphics library that will someday enable every PC to be a high-end, three-dimensional graphics platform.

The inclusion of OpenGL with Windows NT opens up a number of possibilities for the developer community. One result will be a huge expansion in the number of programmers who have the opportunity to develop 3-D applications or to enhance their applications by adding 3-D graphics. Also, more high-end graphics applications will be ported to the PC. In addition, OpenGL will eventually be added to Windows 95, which will dramatically increase the installed base of OpenGL users, further encouraging development of OpenGL applications for a greatly expanded market.

(For a preview of OpenGL, take a look at the new OpenGL screen savers included with Windows NT version 3.5: 3-D Flying Objects and 3-D Pipes.)

Okay, so what is OpenGL?

OpenGL is a very portable software interface for rendering 3-D graphics. It includes approximately 120 commands to draw graphics primitives such as points, lines, and polygons. However, unlike the Windows GDI (graphics device interface), OpenGL primitives are drawn in three dimensions. OpenGL also includes support for shading, texture mapping, anti-aliasing, lighting, and animation. Commands for producing and manipulating higher-level 3-D objects, such as cubes, pyramids, spheres, and the Boeing 777, are not included but can be built from the existing primitives.

OpenGL does not manage windows, read input, or write files. Windows NT, Windows, or some other operating system does the job of managing the windows. An application gives OpenGL a piece of a window or bitmap on which to render.

Silicon Graphics Inc. (commonly known as SGI) originally developed GL, a 3-D graphics language, for its 3-D graphics machine, the IRIS. The process of porting it to another system proved extremely difficult, however. So SGI decided to change GL to make it easier to port to different hardware, operating systems, and windowing systems. The result was OpenGL.

While SGI still maintains IRIS GL, all new work and enhancements are being made to OpenGL. The enhancements and changes to OpenGL are decided by the Architecture Review Board (ARB), whose founding members are Digital Equipment Corporation, IBM, Intel, Microsoft, and SGI.

Benefits for graphics workstation users

OpenGL runs best on high-end 3-D graphics workstations, such as the SGI boxes used for Jurassic Park. Of course, OpenGL running on a Pentium PC with an enhanced VGA card isn't going to come close to the performance of the same application running on an SGI Crimson box. However, the Crimson box will set you back close to $50,000.

So if you don't have $50,000 to drop, the addition of OpenGL to Windows NT provides a number of benefits. For the graphics workstation community, it is low-cost, scalable, and portable. It means that Windows NT can now serve as a low-cost platform for developing and running high-end graphics applications, including CAD/CAM (computer-aided design/computer-aided manufacturing), and thus can replace more expensive graphics workstations. This means a standard Pentium-based PC can become the basis for a graphics workstation.

Windows NT runs on small, portable laptops and large, multiple-processor file servers. You can easily try out 3-D applications or application development on your existing desktop computer and upgrade when you need the extra power. It also runs on the 386, 486, Pentium, MIPS, Alpha AXP, and PowerPC processors.

In addition, Windows NT can easily run standard Windows-based applications. The same system that runs your advanced graphics applications can run word processors, spreadsheets, and other applications for Windows. No need for multiple computers, expensive proprietary applications, or troublesome emulators.

And for developers

Including OpenGL in Windows NT provides a number of benefits for developers:

• Windows NT now provides a way to add 3-D effects to applications. You won't need to buy a third-party library, because OpenGL is included with the system. Applications that traditionally haven't used 3-D graphics can now include 3-D graphics enhancements.

• OpenGL simplifies development of 3-D applications. The number of 3-D drawing and rendering applications should increase, because programmers no longer have to develop their own 3-D graphics libraries.

• It creates the potential for new, exciting 3-D games for Windows. Instead of having to look down on the game board, you can now view the action from the edge of the board.

• It provides a standard 3-D graphics library for the Windows environment.

• It sets a standard that hardware manufacturers can use to create high-performance video cards. Graphics card manufacturers can improve OpenGL performance by performing many OpenGL operations in hardware. In the near future, real-time 3-D graphics will be available on the desktop for a reasonable price.

"Making OpenGL available across our operating system platforms will move 3-D from the esoteric to the mainstream," said Gilman Wong of Microsoft's OpenGL development team. "What I mean by that statement is that 3-D is mostly used in very specific markets, such as games, CAD, maybe high-end graphics design, and the occasional business chart. Providing an industry-proven API like OpenGL will greatly reduce the engineering effort of incorporating 3-D. This in turn will hopefully stimulate and foster its use in a greater variety of applications."

Portability

Due to the ease of porting an OpenGL program from one system to another, it shouldn't take long for OpenGL applications originally developed for SGI, DEC, or IBM systems to appear running under Windows NT.

Win32 applications can run with only a recompile on a variety of platforms, including those with one or more Intel, MIPS, Alpha, or PowerPC processors, and OpenGL applications written for Windows will inherit the built-in portability of the Win32 API.

When OpenGL is ported to Windows 95, it will dramatically increase the installed base of OpenGL users. Companies currently developing applications for the high-end graphics workstation market will suddenly have a much larger possible market for their products. It will also be easier to sell a software package that doesn't require a special dedicated computer system, reducing the expense considerably.

Hardware manufacturers are making enhancements, too

To improve the performance of OpenGL on the PC platform, several video card manufacturers are developing cards and drivers that implement many OpenGL commands in hardware instead of software.

While a properly written OpenGL program will be able to run on a system with or without a hardware accelerator, OpenGL was designed with hardware accelerators in mind. The hardware accelerator will give the program better performance and possibly more capabilities.

The performance of these cards varies depending on how much you pay. They vary in price from several hundred to tens of thousands of dollars. It will soon be possible to get the performance of an SGI Crimson on your desktop at a fraction of the price.

Moving from GDI to OpenGL

Incorporating OpenGL is not as simple as just extending GDI to perform 3-D drawing: GDI users are going to find little that is familiar with OpenGL. For example, drawing a line with OpenGL is completely different from drawing a line with GDI. In fact, OpenGL uses a rendering context and only indirectly uses a device context. Current brushes, colors, fonts, and other objects selected into the device context have no effect on OpenGL rendering. Even the GDI mapping modes have no effect on OpenGL.

Still, though their GDI expertise is not directly applicable to an OpenGL world, GDI experts should be happy that a proven industry-standard graphics interface was chosen.

GDI mavens won't have much trouble learning the basics of OpenGL. In many cases, OpenGL and GDI differ more in syntax than in paradigm. The hard part for a converted GDI programmer is going to be learning 3-D graphics programming. OpenGL is a library for rendering 3-D images; it is not designed to hide developers from the intricacies of 3-D programming. A beginning OpenGL 3-D graphics programmer should read a 3-D textbook before getting too involved with OpenGL. In addition, several books have already been written about OpenGL. (See "OpenGL resources" in the "Additional Information" section at the end of this article.)

Program managers can also rejoice. They can add 3-D graphics to their programs by hiring OpenGL programmers. These OpenGL programmers need to know little or nothing about Windows, because once the display context is set up there is no additional GDI work needed.

Moving toward 3-D Windows

The addition of OpenGL makes the Windows NT platform more attractive to scientific and technical computer users. It shouldn't be long before desktop applications start taking advantage of the rendering capabilities of OpenGL.

The Developer Network Development Library is your best place to get started learning about and using OpenGL. The OpenGL Programmer's Reference appears in the January release of the Development Library as part of the product documentation for the Win32 Software Development Kit. In addition, you'll find various technical articles about OpenGL under Technical Articles/Windows (32-bit)/GDI in the Development Library.

Dale Rogerson is a really swell guy, good-looking, and a snazzy dresser, too. He lives in Corpus Christi, Texas with his pet orangutan, and commutes each day to Redmond, Washington in his Cobra gunship.

Additional Information

Open GL Resources

General graphics textbooks

Computer Graphics: Principles and Practice, James D. Foley, Andries van Dam, Steven K. Feiner, and John F. Hughes, Second Edition, Addison-Wesley, 1990. (This is THE book on computer graphics.)

Computer Graphics, F.S. Hill Jr., Macmillan Publishing Company, 1990.

OpenGL information from the ARB

The OpenGL Architecture Review Board (ARB) has published two books that are a must for all OpenGL programmers: OpenGL Programming Guide and OpenGL Reference Manual.

Another source of information is a Usenet newsgroup: comp.graphics.opengl. This newsgroup publishes an informative frequently-asked-questions (FAQ) list. Also, OpenGL programs for a variety of platforms written by the OpenGL community-at-large can be downloaded from sgi.com via anonymous ftp. Look in the \OpenGL\Contrib directory.

Articles on the Windows NT implementation of OpenGL

"Windows NT OpenGL: Getting Started" by Dennis Crain in the Development Library explains the functions added to Win32 to support OpenGL.

The Microsoft Systems Journal has published two very good articles on beginning OpenGL programming for Windows:

• "Advanced 3-D Graphics for Windows NT 3.5: Introducing the OpenGL Interface, Part I," by Jeff Prosise, Microsoft Systems Journal, Vol. 9 No. 10, October 1994.

• "Advanced 3-D Graphics for Windows NT 3.5: The OpenGL Interface, Part II," by Jeff Prosise, Microsoft Systems Journal, Vol. 9 No. 11, November 1994.

Both articles can be found in the Development Library.


Programming with Microsoft Visual Basic: Error Handling for Multiuser Database Applications

Visually Basic: Error Handling for Multiuser Database Applications

Robert Eineigl
Information Technology Group

January 9, 1995

Error handling. Not a popular topic among programmers. It's like doing the dishes—necessary, but not exactly most people's idea of a good time. This article will change all that. Wait! Before you get too excited, I was only kidding!

While I can't promise that error handling will be fun, I do want to emphasize that for programs whose focus is data access for multiple concurrent users, error handling is absolutely necessary and requires important design consideration.

In the past, single-user programs needed error-handling routines to cover contingencies that programmers couldn't control, such as a user supplying incorrect information to a prompt or removing a floppy disk from the drive while the program was accessing the disk.

But with the transition from procedural, sequential programs for single-tasking operating systems such as MS-DOS, to event-driven, GUI-centric programs for Windows, the code required to handle unforeseen states or unpredictable contingencies has increased considerably.

Indeed, the need for adroit handling of the inevitable conflicts for programs that provide multiple-user access to shared data sources may require the dedication of up to half the code to error-handling logic.

This article provides a starting point for designing data access programs to incorporate robust error handling.

The basics

Visual Basic has no centralized error-handling mechanism. Because of its event-driven architecture, the procedure call stack mechanism does not provide a predictable order of events upon which to base error-handling logic. Instead, each event procedure or user-defined Sub or Function must contain a local scope handler.

The following code snippet shows the skeleton for a local error handler in a Click event procedure:

Sub ClickMeYouFool_Click ()On Error GoTo

localh

' Label for local resume.

reslabel:

' Code body here.

' Exit sub to bypass local handler.

Exit Sub

localh:

' Case on value of built-in Err function.

Select Case Err

Case 3009, 3046, 3202:

Resume reslabel

Case 3008, 3188, 3189:

Resume Next

Case 3046:

' Display error to user.

MsgBox Error$

Resume reslabel

Case Else

Exit Sub

End Select

End Sub

This approach requires that all the logic needed to cover every possible consequence in this local procedure reside in the local handler. In cases where the local procedure is fine-grained, with code that has a precise focus or few resultant error scenarios, this approach works fine. The error logic is located only in the procedure where it's required and thus easily maintained.

However, typically in event-driven programs the same error-handling logic is needed to cover many procedures. Here a single, central error-handling function or a suite of central, globally scoped error-handling functions is better than placing duplicate code in every procedure that needs coverage.

The advantages of this architecture include easier maintenance and troubleshooting, smaller executables, and a program designed around error logic.

Error central

"Well," you may have the impertinence to ask, "if Visual Basic provides no central global error-handling mechanism, how do I implement one?" (Thank you for asking; your check is in the mail.)

The answer is: We still need a local-scope error trap for each procedure where data-access contention or network jitters may cause errors. But, we call a central error function from the local handler, passing the values Err, Error$, and Erl—the error-related internal functions—to the global handler.

The advantage is that the local error handler can start out totally generic and can be pasted into every procedure that needs coverage, with one minor modification—the label for the handler. Because line labels, whether alphabetic or numeric, are form or module level in scope, the label must be altered slightly for each procedure. Note that when used in the On Error GoTo linelabel statement, the corresponding label must be defined in the same local procedure as the On Error statement.

The following snippet is a generic template for a local handler that calls a central error handler for instructions and interprets the instructions for the local procedure's context.

localh:

Dim rc as Integer

rc = ErrorAll(Err, Error$, Erl, localh)

Select Case rc

Case ABORT: ' 1

Case GO_ON: ' 2

Case RE_TRY: ' 3

Case COMMITIT: ' 4

Case ROLLITBACK: ' 5

Case PROMPTUSER: ' 6

End Select

The line label, localh, would have a suffix added to it to match each procedure into which it is pasted.

I have chosen six actions to take upon return from the central handler, ErrorAll. Although somewhat arbitrary, these six choices cover the major responses to multiuser contention or network errors such as time-outs. The important point is to locate the decision logic in one global function.

The central function, ErrorAll, accepts as parameters the current value of the built-in error functions. We must store the value of the built-in functions in variables to pass them because these functions are reset to zero when a Resume or Exit Function is encountered. (Please search the online Help under Err for more information.)

The following illustrates the idea:

Function ErrorAll (errnum As Integer,

errstring As String, errline As Integer,

localh As String) As Integer

' In case of errors in this handler!

On Error GoTo localh_ErrorAll

ErrorStruct.Errnum = errnum

ErrorStruct.ErrorString = errstring

ErrorStruct.Errline = errline

' Now walk the list of handled errors.

Select Case ErrorStruct.Errnum

Case 602 ' general ODBC error

' Call central parsing function

' and pass in initialized structure.

Select Case ODBC_Parse(ErrorStruct)

Case ABORT

ErrorAll = ABORT

' Etc.

End Select

Case 3022 ' duplicate key

ErrorAll = PROMPTUSER

Case 3008, 3188, 3189:

If localh = "localh_Edit" Then

ErrorAll = ABORT

Else

ErrorAll = RE_TRY

EndIf

Case 3046:

ErrorAll = ROLLITBACK

Case Else 'an unforeseen problem

ErrorAll = GO_ON

End Select

Exit Function

localh_ErrorAll:

' Display local errors to debug window.

' Debug.Print Err, Error$.

Resume Next

End Function

The use of the ERRORSTRUCT structure allows a generic form or MsgBox to display information to the user, if needed, particularly if the action chosen is PROMPTUSER. For example, the string type fields would be filled with specific information for each error, to be used in a MsgBox or error form:

ErrorStruct.Headline = "Error: Could Not Lock Table"

ErrorStruct.ResponseMsg = "If the problem persists, check

with co-workers"

In the full-blown ErrorAll, every contingency would be covered in the Select Case statement and the appropriate action chosen to return to the local handler.

Notice that we pass an additional parameter, localh As String, to the ErrorAll central function. This allows the central logic to differentiate between different local handlers and customize the response for that particular procedure.

Also note the call to another function, ODBC_Parse, in response to a general open database connectivity (ODBC) error. The Error$ (or the variant form Error) function contains the full error message returned from whatever ODBC component caused the error. A common mistake with ODBC errors is to try Error$(Err) to retrieve the full error message. Instead, the contents of the unqualified function, passed into the central handler and saved in ERRORSTRUCT, can be passed to a function such as ODBC_Parse and parsed to find the root cause of the error, such as a Microsoft SQL Server error, with the appropriate response scenario returned.

The following code would be placed in the module containing the ErrorAll function:

Type ErrorType

Errnum As Integer

ErrorString As String

Errline As Integer

Headline As String

ProblemMsg As String

ResponseMsg As String

End Type

Global ErrorStruct As ErrorType

Global gbErroroff As Integer

' Constants for the major response scenarios.

Global Const ABORT = 1

Global Const GO_ON = 2

Global Const RE_TRY = 3

Global Const COMMITIT = 4

Global Const ROLLITBACK = 5

Global Const PROMPTUSER = 6

Global Const MaxRetries = 20

Customizing the local handler

Now that we have the central error handler in place, we need to tune the central logic for the particular application being created. The advantage is that, if the design team decides that the proper response to a certain locking error should change from a RE_TRY to ABORT, the change is simply made in ErrorAll and is automatically propagated to the appropriate local handler.

Taking the generic local handler and customizing it for use with the central handler, we have the following code:

Sub Edit_A_Record ()

Dim Retries As Integer

On Error GoTo localh_Edit

If gb_erroroff Then On Error GoTo 0

retry_label:

Select Case g_whichrecordset

Case "Dynaset"

ds.Edit

Case "Table"

tb.Edit

End Select

Exit Sub

localh_Edit:

rc = ErrorAll(Err, Error$, Erl,"localh_Edit" )

Select Case rc

Case ABORT: ' 1

msg$ = "Due to interference from other

insufferable users, "

msg$ = msg$ & Chr$(13) & Chr$(10) & "I am

aborting this transaction!"

MsgBox msg$

Exit Sub

Case GO_ON: ' 2

Resume Next

Case RE_TRY: ' 3

FreeLocks

Retries = Retries + 1

If Retries > MaxRetries Then

msg$ = "20 attempts to obtain an edit lock

have failed."

msg$ = msg$ & Chr$(13) & Chr$(10) &

" Aborting this transaction!"

MsgBox msg$

Exit Sub

End If

tm = Timer

' Wait 1 second then retry.

While Timer - tm < 1

DoEvents

Wend

Resume retry_label

Case COMMITIT: ' 4

CommitTrans

Exit Sub

Case ROLLITBACK: ' 5

Rollback

Exit Sub

Case PROMPTUSER: ' 6

MsgBox CStr(ErrorStruct.Errnum) & " " &

ErrorStruct.ErrorString

Resume retry_label

Case Else

MsgBox "I am clue-free. Now quitting!"

Exit Sub

End Select

End Sub

A global Boolean variable, gbErroroff, is a recommended technique to disable error trapping for the entire project. Setting it to True during the debugging process helps find errors masked by the active error trap.

The local handler is the best place to glue the central handler's logic to the case at hand. The local handler need only deal with the major action scenarios, such as those I have chosen to illustrate, while the central handler does all the parsing and sorting of the raw errors.

Summary

The use of a central error handler can simplify the process of making a multiuser program robust and responsive. By setting up the handler from the project's inception and adding new scenarios as needed, some frustration and duplicated effort can be avoided. An additional benefit is that once the central error logic is developed for one Visual Basic application, it can be reused with minimal changes in other multiuser programs.

Robert Eineigl works in Microsoft's Information Technology Group, building database systems coupled to clients written in Visual Basic. He also disturbs wildlife by playing his custom-made, oversized trumpet.


'Round the World with CompuServe

Service provides lots of online developer resources

Darrell Craig
Developer Network Product Manager

Software developers compete in an industry that is sometimes biased toward North America and the English language.

Luckily, online services provide a mechanism for transcending linguistic barriers—a developer with a modem and the appropriate communications software has access not only to information available to North American developers, but also to valuable localized information, country-specific information, and local support.

For those who have not tapped into this virtual community of online software developers, this article should provide a starting point for exploring some of the developer-related services available on the CompuServe Information Service (CIS). Online veterans may discover some new areas to investigate.

Forums galore

CompuServe is available in more than 120 countries. It is the oldest and largest online service, and it has more than 800 computer and software vendor forums, plus well-established developer-related forums.

International software developers will find local-language and content-based services in Argentina, Australia, Chile, France, Germany, Hong Kong, Hungary, Israel, Italy, Japan, Mexico, New Zealand, Netherlands, South Africa, South Korea, Spain, Sweden, Switzerland, Taiwan, and the United Kingdom.

Microsoft sponsors the following local-language forums: MS Benelux, MS Central Europe, MS Central Europe Systems, MS France, MS Italy, MS Spain/Latin America, and MS Sweden.

The benefits of participating

Developers benefit in many ways by participating in these forums. By using the forums to exchange messages, developers can share programming tips and tricks, offer support to others, communicate directly with Microsoft staff, and even conduct business from time to time. The MS Central Europe forum (GO MSCE) has both active message threads and continuously updated libraries of downloadable files.

For example, on a recent day 13 files were uploaded to the MS Tricks and Tips library section in the MS Central Europe forum. Other categories include Multimedia and a busy Shareware and Freeware library (which includes a popular file with 900 icons for Windows 3.x). All German-speaking developers, regardless of location, may want to peruse this section. The MS France forum (GO MSFR) has particularly active message threads on development issues related to the Windows SDK, Win32 SDK, and Microsoft Foundation Class Library (MFC). The MS France forum also includes valuable files such as the French edition of VBRUN300.DLL (search for file- name VBR300.ZIP).

Another great source of information for international developers is the Windows SDK Extensions forum (GO WINEXT), with libraries dedicated to the Far East SDK and the Arabic/Hebrew SDK.

For example, the Far East SDK library includes a wealth of resources, including Microsoft Far East TrueType Font Files version 1.0, an updated version of WIN87EM.DLL that ships with Windows 3.1J, the August 1994 version of the People's Republic of China (PRC) glossary, and more.

CompuServe also has many product-specific forums. The FoxPro forums (GO FOXFORUM and GO FOXUSER) are among the best examples of what can be done online for the software developer. The libraries of both these forums contain lots of timely, valuable information for developers.

A recent random peek in the FOXFORUM library section on Windows platform development reveals a job listing for a two-month contract in Germany, a public domain integrated browser, and a utility allowing users to preview and print font samples based on installed fonts in Windows 3.1. Other product-related forums of relevance to developers can be found by typing GO MSDEVPROD.

The Microsoft Developer Network delivers a customized version of WinCIM, an application that serves as a graphical front end to CompuServe, in its Development Library. WinCIM provides icons that let you jump easily and quickly into the developer-related areas of the Microsoft Connection area on CompuServe. WinCIM is currently available in English, French, and German versions; the Spanish-language version is scheduled for release in late 1994.

The Development Library also includes information on joining the CompuServe Information Service. For more information on CompuServe within the United States, call (800) 524-3388 and ask for representative 230. Outside the United States, call (+1) (614) 529-1340 and ask for representative 230.

Darrell Craig is a marketing maven in the Microsoft Developer Network. He was voted most likely to succeed by his fellow floor-show participants during the most recent COMDEX.


Rx for Healthcare Info Management Pains

Windows NT Server and Microsoft SQL Server help provide the cure

Sherri Wender
Marketing Consultant

As is the case with most healthcare providers, efficiency and productivity are increasingly important to the United Kingdom's National Health Service (NHS). Following major reform in 1991, the previously centralized national health program is now structured so that each hospital runs as a self-managed provider, competing with neighboring hospitals for contracts to deliver health services.

This means that each institution's income depends on bidding for contracts successfully. Because the requirements for contracts may change from year to year, hospitals now must be able to meet purchasers' changing needs flexibly and rapidly. This makes it hard for hospitals to predict their long-term role, size, and information requirements.

To be successful in this new environment, managers and clinicians must have rapid access to information upon which to base both operational management and strategy. Effective information management becomes crucial.

New system needed

Until the recent reforms, regional health authorities procured and implemented information systems for hospitals. These systems were designed primarily to meet central rather than local needs. Ease of use was not a priority.

These systems, designed primarily for data collection, in general resided on minicomputers or mainframes and ran a variety of unintegrated software packages. Accessing or analyzing information and generating reports, particularly in a timely manner, was very difficult.

With the advent of health-service reforms, an increasing number of services and organizations needed to gain access to common information, and the lack of database connectivity between these systems created huge problems.

The absence of a comprehensive system for handling all patient-related information, including diagnosis, treatment, and finances, resulted in higher healthcare costs and a lack of information needed to support management decisions effectively.

In response to this problem, West London NHS Healthcare Trust was selected as a national pilot site for the development of a new breed of information system. This new system was designed to serve as the model for information delivery for the National Health Service patient information system.

The system had to be easy to maintain, scalable, flexible, secure, and user-friendly. Nurses, doctors, and administrators needed to be able to capture and have access to complete, accurate, up-to-date information about a patient. All clinicians needed access to records to help audit their areas of responsibility.

Mike Morgan, director of application development for the West London NHS Trust and a former practicing physician, was chosen to lead a three-person development team that was tasked with meeting these ambitious objectives.

Visualizing a solution

The ability to take advantage of reusable components in development to save time and money was particularly important to Morgan. After evaluating the alternatives, he decided that a solution using various Microsoft tools and server products would provide better functionality, closer integration, and more cost benefits than the alternatives.

The new system was developed with the Microsoft Visual C++ development system and the Visual Basic programming system. It runs the Windows for Workgroups operating system on the front end and the Windows NT Server network operating system and Microsoft SQL Server on the back end. The smaller installations use the Microsoft Access database management system.

The development team's positive experience with the use of Visual Basic in modeling the new system persuaded it to use Visual Basic as a key part of actual system development. "We learned quickly we had underestimated the power of Visual Basic. We thought it was only a prototyping tool, a toy. We were wrong!" Morgan said. "Both the speed of developing the application with Visual Basic and the speed of the application itself impressed us. We immediately saw what a strong complement Visual Basic is to Visual C++, so we used both."

Morgan's team developed the core tools, such as dockable button arrays, dockable forms, and custom data entry VBXes, in Visual C++ and then reused those tools in Visual Basic. "We used Visual C++ to develop our own VBXes, optimizing for speed, and then Visual Basic easily integrated the functionality written in the VBX," explained Morgan. "Using the reusable, prebuilt code in the Microsoft Foundation Class Library, or MFC, definitely shortened the development process for us."

In addition to taking advantage of MFC, Morgan's team made extensive use of open database connectivity (ODBC) and OLE object technology. "The built-in ODBC support was important to us," Morgan said. "OLE object technology was also a significant part of our development efforts. For example, we were impressed with the PivotTable dynamic views functionality in Microsoft Excel and wanted to emulate that in our reporting system. We started to design the same functionality and then realized that with OLE object technology in Visual Basic we could just embed the PivotTable. We were able to add a tremendous amount of functionality without having to redevelop."

Morgan's developers also wanted to make all the windows include ToolTips and wanted resizable windows. So they bought off-the-shelf VBXes and added that functionality in Visual Basic in a day. "We also created a ‘specialist' integrating functionality so it is easy to reshape and remold the application without having to recompile," he added.

Technical info and server products ease integration

The Microsoft Developer Network played an important part in the process of creating the new system by providing the developers with technical information and resources—such as source-code examples and articles about developing software under Windows NT in its Development Library, and software development kits (SDKs) via its Development Platform. In addition, the developers benefited from the support of the Microsoft Public Sector team in the United Kingdom.

Windows NT Server and Microsoft SQL Server, both part of Microsoft BackOffice, also eased the development process. Explained Morgan, "We wanted to get to where we could manage all of our resources in an integrated fashion from the desktops throughout the whole system. We don't view networking as separate. The benefits of an integrated desktop and file-server operating system rapidly became apparent."

After looking at the cost/benefit of Microsoft SQL Server and comparing it to other solutions, Morgan said his team realized that it could get better performance and save money with a dual Pentium AS running Windows NT Server and Microsoft SQL Server.

"One of the pluses of Windows NT Server is that APIs are the same for both client and server. Additionally, because of the nature of medical records, total security is critical—Windows NT Server gives us a reliable, secure foundation," Morgan pointed out. "Using Microsoft SQL Server Programmer's Toolkit, we found it easy to integrate SQL Server with other data and systems. Windows NT Server and Microsoft SQL Server can scale to as many or as few PCs as desired, which eliminates the need to have a total hardware change."

Voilà, Unity

In January 1994, at a development cost of only £200,000, Unity, as the new system is called, was completed.

The system, which has undergone extensive pilot testing, integrates information from the wide number of data sources. When fully installed it will run with 4 servers and more than 100 client PCs; each server manages from 1 to 2 gigabytes of data.

"Without the flexibility of a product like Unity, it would not be possible to develop healthcare information systems capable of responding at the same rate of change as we're experiencing with healthcare reform. The key to Unity is the rapidity with which you can change information," pointed out Laurence Pearce, manager of information strategy and development for the West London NHS Trust.

Unity contains two main programs: a toolkit and the information desktop. The toolkit maps the information requirements of an organization into an object-oriented model, providing direct benefits to end users. Rather than mapping information requirements directly to database structures, the toolkit builds up a reference of where elements of information may be accessed. This allows Unity to integrate data from a large number of platforms and enables users to query across multiple platforms transparently.

Once the object model and security issues have been established, the toolkit builds a template that configures the information desktop that each user sees. This information desktop is dynamic and self-building so that when new information is added to the system, it can automatically be made available to end users.

The transition from one database to another is seamless to the user. Because all types of information, including multimedia, are handled in an identical manner, the user sees only one consistent view of the organization's information. The system is designed for easy setup and maintenance, since the front end is automatically created for each user based upon the defined data objects and the user's access rights within the system's flexible configuration. It is also easy to extend and modify—any number of new data sources can be added to the system, which are then automatically available to users.

Users can easily customize their desktops to display information that is relevant to them. Custom address books, toolbars, and drag-and-drop reporting make it easy even for novices to use.

Bucking traditional systems

Morgan views a flexible approach as dramatically different from the traditional systems approach. "Previously you would sit with the user and work through what the system needed to do. You'd get specifications, and then a year later you'd have a system that was no longer what was needed. You couldn't keep up to date. Now it's easy."

In addition to providing a flexible, secure environment, Unity has reduced costs and improved efficiency and quality. At the pilot site, the elimination of overlapping administrative costs has saved £200,000 annually, a figure that is expected to rise to £300,000 by the third year.

Users find the system easy to learn and use, which reduces training costs. Quality-of-care improvements will lead to a better service at lower cost. According to a recent study, if the savings estimated at the pilot site were replicated across the NHS, the total amount saved could be as much as £100 million in as little as five years.

This approach to handling information in an object-oriented fashion has created interest within a number of other industries that face similar problems in data integration and management. In response to this demand, Morgan has independently taken Unity forward as a commercial product. Through his company, Open Mind Design Ltd., he intends to make the solution available to solution providers and end users in a large number of industries.

For more information

For more information about Microsoft products, call the Microsoft Sales Information Center at (800) 426-9400. In Canada, call the Microsoft Canada Customer Support Centre at (800) 563-9048. Outside the 50 United States and Canada, please contact your local Microsoft subsidiary. Dr. Mike Morgan can be reached at (44) 181 568 1297 for information about Unity.

Sherri Wender is a marketing consultant who focuses on the software and telecommunications industries. She spends her free time studying the behavior patterns of her three cats.


Survey Gives Snapshot of How OLE Is Being Applied

Hundreds of commercial OLE products now shipping

Dave Seres
Developer Relations Senior Project Manager

In a recent survey conducted by the Microsoft Developer Relations Group (DRG), vendors identified 315 commercial OLE products, many of them already 32-bit applications, as shipping by the end of 1994. These applications are supplied by more than 250 different software vendors. (Since the survey was conducted, vendors have identified an additional 118 products that have support for OLE, bringing the total to 433.) Every major software vendor, including Lotus, Borland, and WordPerfect, is committed to shipping OLE-enabled products.

This survey indicates that support for OLE is growing and that end users expect advanced OLE services in their applications. More than one-third of these applications support the full range of OLE services, including OLE Visual Editing, OLE Drag and Drop, and OLE Automation, as both a container and a server.

As an enabling technology for component software, OLE breaks down the barriers between software applications supplied by different vendors, allowing users to work in a single, integrated workspace. Customized OLE components can be bought commercially and plugged into other OLE-enabled applications, extending packaged applications to fit more specialized needs.

OLE is available today on Windows, Windows NT, and the Apple Macintosh, and will soon be on UNIX and other platforms.

OLE used in corporate applications

To date, more than 70,000 developers have acquired the Microsoft OLE Software Development Kit (SDK), making it clear that leading industry and corporate application developers are creating OLE-enabled applications. Major corporations, such as Reuters, Bankers Trust, and Deloitte & Touche, are developing enterprise-wide OLE-based applications.

OLE is being applied across the entire software spectrum on both the desktop and server. Applications include databases, financial tools, presentation graphics, engineering design, multimedia, communications, workgroup systems, personal productivity products, systems management, and manufacturing.

OLE definitions

The following terms are used to identify specific OLE features supported by applications shown in these statistics:

Linking container means that the application can contain linked objects from documents created using other applications.

Linking server means that the application can create objects that can be linked into other applications.

Embedding container means that the application can contain embedded objects created using other applications.

Embedding server means that the application can create objects that can be embedded within other applications.

Visual Editing means that applications supporting Visual Editing are able to edit embedded objects directly within the document, without opening a different application window.

Automation: An application can drive other applications means that the application includes a programming language, a scripting language, or a macro language that can be used to control other applications that can be driven through OLE Automation.

Automation: An application is driven by other applications means that the application makes its services available to automation controllers by exposing its commands and properties. In this way, other applications can drive the processing of the application.

Drag and Drop: Drop target means that objects can be dragged out of other applications and dropped directly within the application.

Drag and Drop: Drag source means that objects within the application can be dragged out of the application and dropped into other applications.

Dave Seres is a senior product manager and leads the OLE marketing team in the Developer Relations Group. He's been involved with OLE for nearly three years and earlier worked with the development team.


The Reasons for the New Windows 95 Ship Date

Recently Microsoft announced that retail availability for the Windows 95 operating system will probably be delayed until August 1995. The main reason for this delay is the need to ensure hardware and software compatibility with the millions of existing Windows installations. There are no significant architectural issues that have caused the delay, according to Brad Silverberg, Microsoft senior vice president.

Concurrent with the scheduled shipment of Windows 95, Beta 3, to technical evaluators in March, the Microsoft Developer Network will ship Beta 3 with the associated software development kits (SDKs) and device driver kits (DDKs) to all Level 2 members. (Note: You will need a 32-bit compiler to develop applications for Windows 95.)

Microsoft is disappointed about the delay and understands that this may impact your planning. The company extended an apology to Windows 95 software developers, stating that it was committed to keeping all developers informed of its progress on Windows 95.

Below are answers to some questions about the status of Windows 95.

Q. What are the main reasons for the delay?

A. Feedback from our second round of beta testing has been extremely positive, but it also showed that we needed a little more time to get the product right. The biggest hurdle we still face is achieving compatibility with the huge combination of software and hardware on the market today. The challenge of providing innovation, ease of use, speed, and compatibility with more than 60 million machines and tens of thousands of programs is something that has never been encountered before.

This has delayed us a bit, but we have also come up with some innovative ways to achieve our goals. To ensure that we meet our quality goals for Windows 95, we are undertaking huge beta and internal testing efforts. We are working with third-party testing houses. We are taking our testers and developers to homes and to small, medium, and large businesses to run through real-life installations and to record the data.

The next major milestone for Windows 95 is called M8, or Beta 3. We expect to release Beta 3 in March 1995.

In the final development phase after M8, we will incorporate feedback from Beta 3 users. The final release to manufacturing of Windows 95 is planned for June 1995. This will mean that Windows 95 will be available in retail channels in August.

Q. When did you find out about the delay?

A. The M7 beta (Beta 2) was released in the COMDEX time frame. Since then, we have been accumulating the test results from this beta. With this data, we recently started working on a revised schedule that was approved by Bill Gates.

Q. I hear installation is a problem. Is this true?

A. The biggest hurdle we face is ensuring compatibility. That said, installation is an area that is still improving, too. We want to make installation a simple, foolproof operation to users with a wide range of hardware and with wide-ranging experience levels.

Q. This is the second announced delay for Windows 95. Why aren't you better at predicting the ship dates?

A. Predicting the ship date for a project the size of Windows 95 is extremely difficult. This is the first time we've done a major upgrade to Windows with such a huge installed base of customers and gigantic array of hardware and software configurations. The compatibility and installation goals are challenging, to say the least.

Q. What makes you sure you will make this new date?

A. We have had the opportunity to analyze the feedback from our second beta, and given that the product is further along in the development process, we have solid information with which to revise our schedule.


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

    • Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

    • Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

    • Remedy: Insert the MSDN Library CD into the CD-ROM drive.