How to: Register Custom ReportListeners and Custom OutputTypes in the Report Output Registry Table

When it looks for a registered ReportListener, ReportOutput.app checks the records in its registry table with the value of 100 in the Objtype field and a value in the ObjCode field matching the first parameter it received. It ignores deleted records in the table, and uses registry records with a value of 110 in the ObjType field to apply additional filters limiting the records to be considered.

When it has identified the correct record, ReportOutput.app uses the other fields in the record to instantiate a reference to your designated ReportListener-derived class.

In this topic you learn how to create records in the registry table so ReportOutput.app can use them in this process.

Note

For more information about registry table structure and use, see Understanding the Report Output Application. For information about creating and specifying a registry table, see How to: Specify an Alternate Report Output Registry Table.

To add a new OBJECT TYPE value to the registry table

  1. Issue the following command to create ReportOutput.app's default registry table on disk:

    DO (_REPORTOUTPUT) WITH -100  && Write registry file
    

    Note

    If the system variable _REPORTOUTPUT contains the name of a Report Output Application other than the default ReportOutput.app in your environment, substitute HOME() + ReportOutput.app, or similar code, to invoke the default Report Output Application.

  2. A BROWSE window appears with registry records for different components using this table.

  3. Examine the current record in the table. This record is a deleted entry showing you how to create a registry record for new ReportListener entries. Notice that its Objtype value is 100, indicating that it provides ReportListener-derived class information, and that its Objcode value is 999, meaning that ReportOutput.app should use this record when asked for a ReportListener of type 999. Also, observe the name of the class in the Objname field (DebugListener).

  4. From the Table menu popup, choose the Recall Records… option. On the dialog that appears, click the Recall button. The DebugListener record is now active.

  5. Change the Objcode value to a different number, such as 55.

  6. Close the BROWSE window.

  7. Issue the following command:

    REPORT FORM ? OBJECT TYPE 55 
    * substitute the number you used in the table if it was not 55
    
  8. The REPORT FORM command generates debugging output.

  9. Save the name of the current registry table for later use, using the following command. For more information, see How to: Use the Report Output Application's Reference Collection.

    lcOutputRegistry = _oReportOutput["-200"] && current registry
    

To add a new class definition to the registry table

  1. Open the registry table you created earlier, and open a BROWSE window.

    USE (lcOutputRegistry) SHARED ALIAS MyRegistry
    BROWSE
    
  2. From the Table menu popup, choose Append New Record. The new record appears at the bottom of the Browse window.

  3. Change the new record's Objtype value to 100, indicating its use. Change its Objcode value to a different value from the one you used earlier, for example 77.

  4. In the Objname field, use the name of a different ReportListener-derived class. For example, you could use "XMLDisplayListener", a class delivered in the Foundation Class (FFC) folder.

  5. In the Objvalue field, use the name of the class's class library. The file extension is optional if the class library is a visual class library (.vcx) but required if the class library is a program (.prg). If you used "XMLDisplayListener" above, you should use "_ReportListener" here.

    Note

    For this example, you can use the full path of the library in this field, or you can SET PATH TO (HOME() + "FFC") when you are ready to invoke ReportOutput.app. However, when you distribute applications, you can build _ReportListener.VCX into your application file and it will be found without a path.

  6. Leave the Objinfo field blank unless the class library you used in the last step is built into an application (.app or .exe) outside your own code. For example, in the DebugListener record, the Objinfo name holds the fully-pathed name of the Report Output Application, because the Objvalue field holds the name of the library built into ReportOutput.app. If you used "_ReportListener" or "_ReportListener.vcx" from the FFC folder in Objvalue, this value should be blank.

  7. Close the registry table. (Although you opened it SHARED, in certain cases ReportOutput.app will require exclusive use of the table.) From the Command window:

    USE IN MyRegistry
    
  8. Ensure that the class library you specified is available on your path, if you did not use its full path in the Objvalue field ealier. Then use your designated class with ReportOutput.app:

    REPORT FORM ? OBJECT TYPE 77 
    
  9. The REPORT FORM command generates output using the class you specified.

To filter records in the registry table

  1. Open the registry table you created earlier, and open a BROWSE window.

    USE (lcOutputRegistry) SHARED ALIAS MyRegistry
    BROWSE
    
  2. Change the Objcode value for the class you specified in the last section to match the value you used for DebugListener earlier. For example:

    GO BOTTOM
    REPLACE Objcode WITH 55
    

    Note

    You now have two classes registered with the same Output type value (55). By default, ReportOutput.app will use the first one it finds (in this case, DebugListener).. In this procedure, you use a filter to take control of which record ReportOutput.app uses.

  3. From the Table menu popup, choose Append New Record. The new record appears at the bottom of the Browse window.

  4. Change the new record's Objtype value to 110, the value specific to Report Output Application configuration records, and its Objcode value to 1, the value specific to filter records.

  5. Filter records do not use the Objname and Objvalue fields. Use the following expression in the Objinfo field. This expression indicates that you do not want to use any classes built in to the ReportOutput.app file, you only want to use external classes:

    ATC("ReportOutput.APP",Objinfo) = 0
    
  6. Close the registry table.

  7. Ask the Report Output Application for a reference to ReportListener using this type. The third parameter below ensures that any cached reference of this type from earlier attempts will be released and you will get a new evaluation of the appropriate class:

    oRL = NULL
    DO (_REPORTOUTPUT) WITH 55, oRL, 2 && reload
    
  8. Verify that the class reference is the second class you added to the table (in the example, XMLDisplayListener):

    ? oRL.Class
    
  9. Open the registry table again, and change the Objcode value or make some other change so the record no longer qualifies as a filter:

    USE (lcOutputRegistry) SHARED ALIAS MyRegistry
    GO BOTTOM
    REPLACE Objcode WITH 2
    USE && close the table again
    
  10. Issue the same commands you used earlier, and observe that you receive a reference to DebugListener this time:

    DO (_REPORTOUTPUT) WITH 55, oRL, 2 && reload
    ? oRL.Class
    

    Tip

    Filters can be based on values in additional registry table fields, because user-defined fields are permitted in the table. For example, you could have a logical field named CustPref, and filter on the value CustPref, signifying which class your application's end-user prefers to use. To work as a filter, an expression has to be something appropriate to a LOCATE statement applied to the registry table. The Report Output Application uses the filter in a LOCATE statement when it searches the registry table for a record for a ReportListener of appropriate output type. For more information about how the Report Output Application uses the Objinfo field to apply a filter, and about how it uses the rest of the registry table columns, see Understanding the Report Output Application.