The Custom FrontPage Component Implementation File

A custom FrontPage component implementation file is either a dynamic link library, a shared library, a stand-alone program, or a script. It can contain software implementing one or more components.

A custom component implementation is analogous to a CGI script. The component’s procedure is given three sets of name-value pairs:

Based on this information, the component must return some HTML representing a page fragment or an entire page.

A component can be implemented with a single procedure.

When using the Standard I/O interface, this procedure is called implicitly by invoking the executable. A Standard I/O component implementation reads the dictionaries from its standard input and writes HTML to its standard output.

When using the DLL or shared library interface, you must export a single entry point named Xxx_Expand, where Xxx is the shortname of the component, exactly as specified (including case) in the component description file.

Types of Custom FrontPage Components

The custom component API supports two types of components, as indicated in the component definition file:

The Insert components will appear in the Insert: FrontPage Component dialog box. The Form components will appear in the Form Properties dialog box, in the drop-down list inside the Form Handler group box.

Determining Why the Component Was Activated

The component attributes dictionary contains six extra synthesized state variables, in addition to the component’s own state variables. They tell you why the component was activated, and give you information about the location of the page.

The Method attribute is used to tell Form components they are being awakened as a result of a HTTP POST method from their own form.

The PageURL attribute provides the web-relative URL of the page on which the component lives.

The DocumentRoot attribute provides the absolute path to the web’s root directory on the local file system. This path uses the local filesystem convention for path separator characters, so on a Windows system it will use a backslash (“\”) instead of the forward-slash (“/”) used in URLs.

The WebURL attribute provides the absolute URL of the web.

The BaseDocURL attribute is new for FrontPage 98; it provides the web-relative URL of the outer-most containing page in which the component is being expanded. This information is useful when the page where the component lives is included inside another document. For example, if a FrontPage component is defined in the top border page of a FrontPage 98 web and then the page “test.htm” that includes the top border is saved, the component will be expanded with PageURL set to “_borders/top.htm” and BaseDocURL set to “test.htm”.

Generating MIME Headers

The HTML generated by the component can be preceded with some optional MIME headers, which control how the resulting HTML is interpreted by the FrontPage Server Extensions. Each header is terminated by a single newline character (“\n”). Indicate the end of all headers with a blank line, so there are two newline characters (“\n\n”) in a row.

All headers are optional. Normally any HTML generated by the component is inserted in-line into the page at the point where it occurs.

You can change this behavior with one of the following types of headers:

header interpretation
Content-type: MIME-type Causes the current SmartHTML page to be replaced with the entire result page following this header.
Location: some-URL Causes the current page to be replaced with the referenced page. The SmartHTML program starts interpreting the some-URL page if it is in this web, or else causes the browser to fetch some-URL. This only works for a dynamically-accessed page (Parse=Dynamic).
Redirect: some-URL Works just like the Location header, but if some-URL is absolute (as in http://myweb/mypage.htm), it causes the browser to fetch it directly instead of going through the SmartHTML program.
Links: url-list A space-separated list of URLs to which this component generates links. If any of the pages in the Links list contain spaces, they must be URL-encoded. For example, “my page.htm” should be output as “my%20page.htm”. This information is used by the FrontPage Explorer’s Link View and the FrontPage Table-of-Contents component.
WriteLinks: url-list If you set any write links, the FrontPage Server Extensions will set the permissions for this file so that Web browsers can write to the file. This allows the component to update the file when used dynamically (for example, a FrontPage Form Results component).  Also, files specified in the WriteLinks: mime header for a component are now treated as ancillary files. Such files will be deleted if the page containing the component is deleted, moved if the page containing the component is moved, etc.
Error: Error-string Components can already specify mime headers to communicate certain information. Now they can specify a new mime header, “Error:”, which causes FrontPage to mark the component’s page as containing an error. In the FrontPage Explorer’s Hyperlinks view, this results in a red-triangle image that appears in front of the page name. Right-clicking for properties on this page displays a dialog that displays the error string as specified by the component.

It is important to understand the difference between the static and dynamic versions of a page in a FrontPage web in order to use the redirection options availabe with the Location and Redirect headers. The static version is exactly as the page appears on disk; the dynamic version has its FrontPage components expanded when the page is fetched and a newly-generated page is returned to the browser. The static version of a page is fetched with a normal absolute or relative URL, such as “http://myweb/mypage.htm” or “mypage.htm”. The dynamic version of a page is fetched through the SmartHTML interpreter with a special dynamic URL prefix, such as “_vti_bin/shtml.dll/mypage.htm”.

The dynamic URL prefix comes in two flavors, depending on the web server. The prefix is either “_vti_bin/shtml.dll/” or “_vti_bin/shtml.exe/”.

There are three page redirection options available to a FrontPage component:

Use the Location header to return the dynamic version of another page in the web by restarting the SmartHTML interpreter on another page in the web. The second page will be expanded with the same form data (if any) and CGI dictionary as the first page. If the second page contains a form with form handler FrontPage components, they will respond just as if the form had been submitted.

Use the Redirect header to get the browser to fetch the static version of another page in the web. You must supply an absolute URL to the static version.

Use the Redirect header to get the browser to fetch the dynamic version of another page in the web. Supply a relative URL to get the dynamic version.

Clientside Components

FrontPage 98 introduces a new reserved attribute, “CLIENTSIDE”, to designate components that have no server-side expansion.  Instead of expanding on the server at save-time or browse-time, a clientside component generates its expansion at edit-time when the FrontPage Editor calls the component’s edit() function.  To accomplish clientside expansion, the component uses three other reserved attributes.

Using the “S-HTML” attribute, a client-side component can specify the exact HTML that will appear between its startspan and endspan in the final saved page.  This can be combined effectively with the existing “PREVIEW” attribute to display one block of HTML while the component is viewed in the editor, and an entirely different block of HTML when viewed in the browser. 

For instance, an ASP-based component might want to display a pretty version of its name and logo while the user is editing the page, but be interpreted as real ASP code once the page is browsed.  If it declares itself to be a clientside component, it can use the PREVIEW attribute to specify the name and logo, and the S-HTML attribute to specify the ASP code. 

Finally, with the addition of the Preview tab to the FrontPage Editor, components have a third environment in which they may want to expand differently.  Using the “LOCAL_PREVIEW” attribute, a clientside component can specify distinct HTML for substitution when the user views the page from the Preview tab.  In the example above, since the component’s ASP code won’t be interpreted before the Preview tab is rendered, the component may want to use LOCAL_PREVIEW to insert a reasonable facsimile of its final output and/or a warning message that the preview is not wholly accurate.

The following table outlines the clientside reserved attributes:

ATTRIBUTE MEANING
CLIENTSIDE This attribute has no right-hand-side value.  If present, it indicates that the component has no server-side expand function, and that the S-HTML, LOCAL_PREVIEW, and PREVIEW attributes should be used instead.
S-HTML The value of this attribute specifies the HTML to be used when the component is written to a page. 
LOCAL_PREVIEW The value of this attribute specifies the HTML to be used when the editor is on the Preview tab.  If the S-HTML attribute does not exist, this value is also used when saving the component to a file.
PREVIEW The value of this attribute specifies the HTML to be used when the editor is displaying the Normal tab.  If the LOCAL_PREVIEW attribute does not exist, this is also what is used on the Preview tab.  If neither the S-HTML or the LOCAL_PREVIEW attributes are present, this is also is what is written to the file.

Additional Reserved Attributes

In addition to the clientside reserved attributes describe above, FrontPage 98 introduces two other attributes that can be used to alter the behavior of a component.

ATTRIBUTE MEANING
PageAspPrefix Whenever a component wants to insert ASP at the very beginning of a document (not in the middle of the page, where the component itself resides), it can use this reserved attribute to specify that block of ASP code.

ASP prefixes appear at the top of the document in the same order as the components which generated them appear in the body of the document (so multiple PageAspPrefix-using components can appear on the same page). FrontPage 98 keeps track of all the ASP prefixes it is responsible for by inserting a special comment into the ASP code that begins with ' FP_ASP.  Also, if not already present, <% and %> are added before and after the ASP provided in the attribute. 

The PageAspPrefix attribute is only checked when the component returns from its server-side expand( ) function, and once the attribute is read and the ASP is inserted at the top of the page, the attribute is stripped out of the component’s attribute list. This means that the PageAspPrefix attribute never actually appears in the component’s WEBBOT syntax.  It also means that the component’s expand( ) function must add the attribute each time it returns, or else the ASP will not be regenerated. Note that the ASP-code referred to by PageAspPrefix must start with <%newline, or the prefix becomes wrapped in <%newline and %>.

SuggestedExt When a component is inserted into a page, it can request that the FrontPage Editor use a particular file extension when the page is saved by using the SuggestedExt attribute. If the page has not yet been saved, the FrontPage Editor will use this attribute to propose a file extension in the SaveAs dialog.  If the page has already been saved with a different extension, the Editor will pop up a message instructing the user how to change the file extension. SuggestedExt is particularly useful when a component relies on a technology that requires a certain file type extension, such as ASP.

DLL and Shared Library Implementation

In the DLL and shared library implementation, the component’s Expand method is passed opaque pointers to dictionary and string objects, and a pointer to an array of functions for accessing and manipulating them. You must include the file “webbot.h” to obtain definitions for these types.

The Expand method’s interface is as follows:

void Xxx_Expand (
        WebBotString* retString,
        WebBotDict*   botAttributes, 
        WebBotDict*   cgiEnvironment,
        WebBotDict*   formData,
        WebBotFuncs*  funcs )

The file “webbot.h” defines two in-line C++ classes, CWebBotDict and CWebBotString, for easy access to WebBotDict and WebBotString parameters:

class CWebBotDict
{
CWebBotDict(WebBotDict* dict,const WebBotFuncs* funcs);
     // Constructs a new CWebBotDict from a WebBotDict.
     
long NumValues(const char* key);
     // Returns number of values for this key.

const char* GetValue(const char* key);
     // Returns a string value for a particular key. 

const char* GetValueN(const char* key, short ValueNum);
     // Returns the nth value of a multi-valued key
     (or the only value of a single-valued key).

const char* NextKey();
     // Returns the next key in the dictionary.
        // Returns 0 when the end is reached. 

void SetValue(const char* key, const char* value)
    // Sets the string value for a particular key.  If the key 
    // has more than one value, it sets the first (0th ) value.

void SetValueN(const char* key, const char* value, short valueNum)
     // Sets the valueNum’th string value for a particular key.

void RemoveKey(const char* key)
    // Removes the key, + all associated values, from the 
    // dictionary

void Reset();
     // Resets the iterator to the beginning.
}

class CWebBotString
{
CWebBotString(WebBotString *string, WebBotFuncs *funcs);
     // Constructs a new CWebBotString from a WebBotString.

void Clear();
     // Resets the string so it is empty.

void Append(const char* stringToAppend);
     // Appends a C string to the string.

const char* GetContents(WebBotString* string);
     // Gets the contents of the string as a C string
}

There can be more than one value for a given key. Use the DictGetValueN and DictSetValueN methods to take advantage of this. Note, however, that there is no guarantee that the order of the entries for a given key will remain the same between calls to the Edit or Expand methods of a FrontPage component DLL. That is, what used to be the first value of a key could get swapped with the second value for the key between calls to the FrontPage component DLL.

The file “webbot.h” defines a pair of macros, BeginWebBotExpand and EndWebBotExpand, that simplify the process of defining an Expand method. BeginWebBotExpand takes five names as arguments:

  1. the shortname of the component (as in botname_Expand)

  2. the name of a CWebBotString variable where you will append your HTML

  3. the name of a CWebBotDict variable holding the component’s attributes

  4. the name of a CWebBotDict variable holding the CGI environment

  5. the name of a CWebBotDict variable holding the form variables (if any)

A very simple “hello” WebBot component can be implemented in C++ as follows:

#include “stdio.h”
#include “../webbot.h”

BeginWebBotExpand(hello,ret,bot,cgi,form)
{
   ret.Append(“<H1>Hello, WebBot World!</H1>”);
}
EndWebBotExpand

For a C language component implementation, you can manipulate the strings and dictionaries using syntax like funcs->MethodName.

The methods provided by the WebBotFuncs structure are as follows:

long DictNumValues(WebBotDict* dict, const char* key);
const char* DictGetValue(WebBotDict* dict, const char* key);
const char* DictGetValueN(WebBotDict* dict, const char* key, short valueNum);
void DictReset(WebBotDict* dict);
const char* DictNextKey(WebBotDict* dict);
void StringClear(WebBotString* string);
void StringAppendTo(WebBotString* string, const char* stringToAppend);
const char* StringGetContents(WebBotString* string);
void DictSetValue(WebBotDict* dict, const char* key, const char* value);
void DictSetValueN(WebBotDict* dict, const char* key, const char* value, short valueNum);
void DictRemoveKey(WebBotDict* dict, const char* key);

The FrontPage component API also supports components which can execute on the client side. If the .inf file describes the component as having clientbinding=DLL, then the clientmodule is a DLL which will be downloaded to the client and executed. The FrontPage Editor displays a dialog warning that a download is about to occur and giving the user an opportunity to cancel. If the user tries to edit a component that is not defined for the current web, or if the FrontPage Explorer is not running or has no current web open, then the FrontPage Editor will use the generic FrontPage Component Properties dialog instead of the custom dialog.

The client-side interface is similar to the server-side interface. A set of opaque pointers is used to pass information from the FrontPage Editor to the FrontPage component. You must include the file “webbot.h” to obtain definitions for these types.

The Edit method’s interface is as follows:

int Xxx_Edit(
      WebBotDict*      botAttributes,
      WebBotFuncs*   funcs
       )

The botAttributes argument is a dictionary of all of the component attributes. This will be empty if the user is inserting a component, but will contain the attributes which were previously added to the dictionary by the component if the user is editing a component which was already inserted. The Edit function should return zero if the user hits cancel, and non-zero otherwise.

The CWebBotDict class, defined in webbot.h and described earlier in this section, may be used in the Edit method as well as the Expand method. The file “webbot.h” defines another pair of macros, BeginWebBotEdit and EndWebBotEdit, that simplify the process of defining the Edit method. BeginWebBotEdit takes two names as arguments:

  1. the shortname of the component (as in botname_Edit)

  2. the name of a CWebBotDict variable holding the component’s attributes

For a C language implementation, you can manipulate the strings and dictionaries using syntax like funcs->MethodName. The same functions are available through the WebBotFuncs structure as described in the Expand method.

When a FrontPage component is first instantiated, either from the Insert: FrontPage Component dialog or the Form Properties dialog, its attribute dictionary is empty.

Since there is no BTL file for client-side DLL components, the component must add any required attributes, including PREVIEW and TAG keys, to the botAttributes dictionary when the Edit method is called for the first time. The purpose of these keys is described earlier, in the documentation for the BTL file format. The only difference is that the PREVIEW string does not need to have <, >, and & characters escaped in the Edit method. An easy test to find out if the component is being created for the first time, rather than modified, is to see if botAttributes.NextKey returns NULL at the start of the Edit method. This test will fail once you have added some attributes to the component.

A very simple “hello” component can be implemented in C++ as follows:

#include "../webbot.h"
BeginWebBotEdit(hello, botAttributes)
{
   botAttributes.SetValue("PREVIEW", "<H2>Hello World!</H2>");
   botAttributes.SetValue("TAG", "H2");
   return 1;
}
EndWebBotEdit

The major advantage to using client-side DLLs for FrontPage components is that the component can implement any kind of property-editing dialog box it requires. This means you’re not just limited to the generic FrontPage Component Properties dialog. You get much greater flexibility on the client side to perform selection actions, such as browsing the local hard drive for files, or displaying a custom color selection dialog box. Another advantage is that the PREVIEW key is generated at run-time, allowing a component to create a much better approximation of the final output. Note that the same DLL file may be used for the client and server side routines.

Example: Creating a client-side DLL

Here is an example to show you how to create a simple client-side DLL which displays a simple dialog box. This example uses Microsoft Visual C++ and MFC.

  1. Start Microsoft Visual C++. From the File menu, choose the New option, and select Project Workspace. From the New Project Workspace dialog, choose the MFC AppWizard (dll) option. Name the project “simple”.

  2. Click the “create” button. Choose either an MFC shared DLL or an extension DLL.

  3. Create a new dialog box resource for the component. Add controls to the resource as desired. For instance, Ok and Cancel buttons and an edit field

  4. Derive a class from the dialog resource using ClassWizard. Name the class “CSimpleDialog”. Attach a value member variable called “m_edit” to the edit field using the classwizard.

  5. Copy the file webbot.h from the SDK into the project directory

  6. Add the following lines to the top of simple.cpp:

#include "simpledialog.h"
#include "webbot.h"
  1. Add the following function to simple.cpp:
BeginWebBotEdit(simple, botAttribs)

{

   CSimpleDialog dlg;
   dlg.m_edit = botAttribs.GetValue("PREVIEW");
   int nResponse = dlg.DoModal();
   botAttribs.SetValue("ExpandTo", dlg.m_edit);
   botAttribs.SetValue("PREVIEW", dlg.m_edit);
   return (nResponse == IDOK);
}
EndWebBotEdit
  1. Add the following function to make the DLL also be a server-side custom FrontPage component DLL. If you don’t add this function, you will need to make a BTL file which expands the “ExpandTo” key to be the resulting HTML text for the component, and set the serverbinding in the .inf file to be BTL.
BeginWebBotExpand(simple,ret,botAttribs,cgi,form)
{
   ret.Append(botAttribs.GetValue("ExpandTo"));
}
EndWebBotExpand
  1. Select the Win32 Release target from the drop-down menu on the toolbar and compile the DLL.

  2. To do local testing, create c:\Program Files\Microsoft FrontPage\bots\simple (that is, create a bots\simple directory under wherever the FrontPage root directory is on the local machine) and copy the newly created DLL into that directory. Later, when the component is ready for release, it should be made platform independent and placed on the server in the root web/_vti_bot/botname directory

  3. Create a simple.inf file in the same directory, using the examples as a guide. Be sure to set the clientbinding and serverbinding keys to DLL. Set the “type” to “insert”.

  4. Run the FrontPage Explorer. From the FrontPage Explorer’s Tool’s menu, choose Recalculate Links. Your component should now show up in the Insert : FrontPage Components listbox in the FrontPage Editor.

  5. Select the Simple Bot. It will prompt you to download the component into the botcache directory. After downloading, the simple component will display its dialog. Enter some text into the edit box and click okay. The preview string contains the text that was entered.

This sample component (including a simple.inf file) can be found in the SDK’s WebBot\simple folder.

IMPORTANT: If your component requires any DLLs, be sure to include them with the component setup so that they can be installed on the system. FrontPage 98 ships with MFC 4.2 DLLs, but in general, you need to make sure that you provide any necessary DLLs that might not be included with FrontPage itself. For this reason, you should make sure that you only install Win32 Release builds of your component, particularly if you use the Microsoft Foundation Classes (MFC). If you use the same module on both the client and server, and you require additional libraries, you are responsible for installing them on both the client and server machines.

Standard I/O Implementation

The Standard I/O component implementation is designed for creating server-side expand methods in any of several scripting languages on UNIX-based servers. You could implement a Standard I/O component using a compiled program, but a dynamically linked library will be much more efficient. The Standard I/O implementation option is not available for servers running under Windows 95 or Windows NT, and it can only be used to implement the server-side expand method, and not the client-side edit method.

The Standard I/O implementation is designed to be as similar to traditional CGI programs as possible. Data is passed to a Standard I/O component in two ways. The CGI environment variables are passed via the process’ environment. The other two dictionaries (the component attributes and the form variables) are merged into a single dictionary, and passed to the component implementation via the process’ standard input file in WWW-FORM-URLENCODED format. This is the same format expected by any standard CGI script that expects to handle form submissions. The standard output file is used to return the generated HTML.

If you want to create a component in a scripting language besides Perl and Tcl (the languages used in the FrontPage SDK examples), you need to make sure that it supports standard I/O, and you need to create a procedure that parses form data from the standard input file into internal data structures. There are many examples of such routines for other languages available on the Internet.

In order to allow the component implementation program to separate the merged name-value pairs into separate dictionaries, all component attribute names are prefixed with the string “_BOT_”. Form variable names are not modified. The _BOT_ prefix is a feature of the Standard I/O binding, and is never used with the DLL binding.

To implement multiple components in a single script or program, your main procedure should examine the custom component variable _BOT_bot, which contains the component’s shortname. You can then switch processing to a component -specific expand procedure based on this value.