home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Journal 1990 - 1995 / CUJ.iso / mac / 1993.txt < prev    next >
Text File  |  1996-02-07  |  3MB  |  101,098 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449.  
  450.  
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606.  
  607.  
  608.  
  609.  
  610.  
  611.  
  612.  
  613. Designing an Extensible API in C
  614.  
  615.  
  616. Charles Mirho
  617.  
  618.  
  619. Charles Mirho is a consultant in New Jersey, specializing in Multimedia. He
  620. holds a Masters Degree in Computer Engineering from Rutgers University. He can
  621. be reached on CompuServe at: 70563,2671.
  622.  
  623.  
  624.  
  625.  
  626. Definition of an Extensible API
  627.  
  628.  
  629. An application program interface is the set of function calls that a software
  630. library exports to applications. These functions, along with their parameters,
  631. are usually prototyped in a header, or include file. In addition to
  632. prototypes, the header file also contains definitions for structures used by
  633. the functions, and #defines for flags and return values. All these components
  634. of the header file make up the complete definition of the API.
  635. An extensible API can accomodate growth in the library without requiring
  636. changes to existing applications (beyond a possible recompile). Listing 1
  637. contains a simple, extensible API.
  638. The function in Listing 1 is useful in GUI APIs. It defines a region of the
  639. display where a mouse click can be trapped. A typical call to the function
  640. might look something like
  641. #define ID_HELP_BUTTON 10
  642. int vertices[] = {10,20, 50,20, 50,40, 10,40};
  643. REGION HelpButton = {sizeof(vertices)/sizeof(int)/2,
  644. &vertices[0]};
  645. .
  646. .
  647. .
  648. DefineHotSpot (ID_HELP_BUTTON, &HelpButton);
  649. The value of ID_HELP_BUTTON varies depending on the application.
  650. ID_HELP_BUTTON also provides a unique ID for the region. The second parameter,
  651. &HelpButton, defines the boundary of the region as a set of vertices. Notice
  652. that the REGION structure is defined in API.H, the header file for the API.
  653. REGION contains a field for the number of vertices in the region, and a
  654. pointer to a list of vertices (coordinate pairs). Early versions of the
  655. library might only support rectangular hot spots (four vertices), but the API
  656. is extensible because more complex shapes can be used in the future without
  657. altering the prototype for DefineHotSpot. Compare Listing 1 to a
  658. non-extensible version of the same API in Listing 2.
  659. Since the region is always rectangular, only two vertices are required,
  660. specifying the upper-left and lower-right corners of the rectangle. While this
  661. function may seem cleaner and more intuitive at first glance, it is extremely
  662. confining. If future versions of the library must support regions with more
  663. than four vertices, then you must choose one of two undesirable alternatives:
  664. You can create an extensible version of DefineHotSpot. Now developers must
  665. learn two functions, since the old version of DefineHotSpot must be retained
  666. for compatibility. The result is a cluttered API.
  667. You must modify existing applications that use DefineHotSpot to support the
  668. new function API.
  669.  
  670.  
  671. Structured Parameters
  672.  
  673.  
  674. The extensible version of DefineHotSpot (Listing 1) uses a structured
  675. parameter, while the non-extensible version (Listing 2) passes all the
  676. parameters through the function prototype. Using structured parameters is one
  677. of the best ways to design an API that is more extensible. As the capabilities
  678. of the library expand, fields can be added to the structures without changing
  679. the function prototype. A good application of this technique is in functions
  680. that return information, such as
  681. int GetSystemInfo (SYSTEM_INFO
  682. * sinfo);
  683. This function is used to get information about devices in the computer system.
  684. The SYSTEM_INFO structure:
  685. typedef struct tagSYSTEM_INFO
  686. {
  687. int num_displays; /* number of attached displays */
  688. int num_printers; /* number of attached printers */
  689. int num_drives; /* number of attached disk drives */
  690. } SYSTEM_INFO;
  691. has fields to hold the important properties of the system. (I kept it short
  692. for clarity.)
  693. Later versions of the API can expand the structure to accomodate new additions
  694. to the system, such as tape drives, as in:
  695. typedef struct tagSYSTEM_INFO
  696. {
  697. int_num displays; /* number of attached displays */
  698. int_num_printers; /* number of attached printers */
  699. int_num_drives; /* number of attached disk drives */
  700. int_num_tapes; /* number of attached tape drives */
  701. } SYSTEM_INFO;
  702. Because the features of the system are passed through the API in the form of a
  703. structure, rather than as separate parameters, it is easy to add a field for
  704. tape drives.
  705.  
  706.  
  707.  
  708. The Size Field
  709.  
  710.  
  711. You can add even more flexibility to structured parameters with the size
  712. field. The size field holds the size, in bytes, of the structure containing
  713. it. When using a size field, you must make it the first field in the
  714. structure, as in
  715. typedef struct tagSYSTEM_INFO
  716. {
  717. int size; /* size of this structure */
  718. int num_displays; /* number of attached displays */
  719. int num_printers; /* number of attached printers */
  720. int num_drives; /* number of attached disk drives */
  721. int num_tapes; /* number of attached tape drives */
  722. } SYSTEM_INFO;
  723. The size field makes it possible for existing applications to use newer
  724. versions of the library without performing a recompile. This is especially
  725. useful on platforms that use dynamic linking, because dynamic link libraries
  726. are often packaged separately and sold directly to customers. Application
  727. developers often have no control over which version of the library customers
  728. are using.
  729. To see how the size field can save a recompile, look at the SYSTEM_INFO
  730. structure again. When the num_tapes field is added, the size of the structure
  731. changes. It would normally be necessary to recompile applications that use the
  732. structure so that static and dynamic allocations reserve the correct amount of
  733. storage. Otherwise, the newer library would write too much data into the
  734. structure parameter, corrupting memory. However, if the first field of the
  735. structure contains the structure's size, and you are careful to add fields
  736. only to the end of the structure, then the structure can be extended without
  737. the need to recompile existing applications. The library simply examines the
  738. size field to determine which version of the structure the application is
  739. passing. If the application is passing the older structure, the size will be
  740. smaller, and the library knows not to fill the extended fields. Listing 3
  741. contains an example.
  742. In Listing 3, the library keeps the declaration of the old SYSTEM_INFO
  743. structure as oSYSTEM_INFO. The oSYSTEM_INFO structure does not appear in the
  744. header file that applications use.
  745.  
  746.  
  747. Interpretation Flag
  748.  
  749.  
  750. Suppose the GetSystemInfo function is extended in the future to report details
  751. about particular devices in the system. You can use the same function to get
  752. the number of displays in the system, and details about the displays the
  753. system is using, as in:
  754. typedef struct tagDISPLAY_INFO
  755. {
  756. int size;
  757. /* size of this structure */
  758. int displayno;
  759. /* display to get info on */
  760. int xpixels;
  761. /* display width in pixels */
  762. int ypixels;
  763. /* display height in pixels */
  764. int bits_per_pixel;
  765. /* bits per pixel */
  766. int planes;
  767. /* video planes */
  768. } DISPLAY_INFO;
  769. You can insure that the GetDisplayInfo function will support this and any
  770. other device-specific structures that come along by changing the original
  771. prototype to
  772. int GetSystemInfo
  773. (int flag, unsigned char *info);
  774. GetDisplayInfo now accepts a byte-aligned pointer instead of a pointer to a
  775. specific structure. The function interpretes the pointer differently,
  776. depending of the value of the flag parameter. You call the function for
  777. general system information with
  778. /* API.H */
  779. #define GET_SYSTEM_INFO 1
  780. #define GET_DISPLAY_INFO 2
  781. .
  782. .
  783. /* application */
  784. SYSTEM_INFO sinfo = { sizeof(SYSTEM_INFO), 0, 0, 0 };
  785. .
  786. .
  787. GetSystemInfo (GET_SYSTEM_INFO, (unsigned char *)
  788. sinfo);
  789. For details on display devices, you call the function with
  790. /* application */
  791. DISPLAY_INFO dinfo = { sizeof (DISPLAY