 ---------------------------------------------------------------------------
 $Id: OLEClient.txt 1.10 2004-02-29 19:56:10+01 erikgrnh Exp $
 ---------------------------------------------------------------------------

 Originator - Mike
 Purpose    - Specification of generic 'OLE' interface and mechanisms
 Version    - $Revision: 1.10 $
 Started    - 14th August 1993

 $Log: OLEClient.txt $
 Revision 1.10  2004-02-29 19:56:10+01  erikgrnh
 Split the specification into a description for the client and a
 description for the server. Embelished with more detail.

 ---------------------------------------------------------------------------

Overview
========

 OLE or object linking and embedding allows an application to share
data with a secondary or server application which can edit that
data and return it. This allows compliant applications to gain
features provided by specific graphics or text servers without having
to reimplement those features again.
 This documentation defines the message passing protocols necessary for
this kind of data sharing.


The client
==========

 A client application (such as Impression) may wish to edit data it is
capable of loading and rendering (such as drawfiles). There are twp options
open for such an application. Either it can provide facilities to edit these
files itself, or use an already resident editor by sharing the file with it.
It seems sensible and easier to choose the second option, in which case
the client needs to ask a 'compliant' server to engadge in a two way data
sharing session. It does so by the use of a OLEServer$<UniqueName> system
variable which the server provides.


The server variable
===================

 Any application which prvides its own file type and is capable of editing
such files may set itself up to be an OLE server. To do so it needs to create
a system variable, outlining the file type it can edit.

 The syntax of this variable is as follows

 Variable name  = OLEServer$Type_XXX
 Variable value = -N <UniqueName> -R <run><Run$Path>

 X          = 0..9 | A..F
 AlphaChar  = 0..9 | A..Z | a..z
 UniqueName = [1..16]*<AlphaChar> (i.e. one to sixteen AlphaChars)
 run        = 'run ' or '/'

 Spaces must be used as separators.

 Typical examples are

   OLEServer$Type_AFF : -N OLESupport -R /Desktop_OLESupport
   OLEServer$Type_FFF : -N StrongED -R /ADFS::Csite.$.Apps.!StrongED


 Tokens
 ------

-N : Name

     This token specifies a unique name to identify the server in
     an OpenSession message. This message is broadcast so it is up to
     the server who recognises the name to respond. This string can
     be up to 16 characters long. When passed in messages it should be
     specified as a 16byte string with all unused bytes zero'd.
     Note the server name should be modeled on the application name
     such as 'OLESupport' used by the support module or StrongED as
     used by the StrongED text editor.

-R : Run
     This token allows a potential client to Wimp_StartTask the server.
     It must provide a run$path string which uniquely locates the
     server. This could be an expanded pathname or more usually
     a system variable. It should be preceded with a run command so the
     whole string can be passed straight to Wimp_StartTask.
     eg 'run <Draw$Dir>'.
        '/<Draw$Dir>' etc



Creating an OLE session
=======================

 An OLE session should be opened by a client application which cannot itself
edit a particular data format and wishes to share the data with a server
in order to do so.

A clients point of view
=======================

(1) The client should check to see if an OLEServer$Type_XXX variable
    exists for its file type.
    (If it cannot find such a variable, then the client may wish to
    use the OLESupport module which simulates the response of a client
    for particular file types. See OLESupDoc for information on how to
    use this module task).

(2)   Having found a server variable, the client should save its data to
    disc and send an OpenSession message with format 0 as a broadcast,
    using the unique name specified in the variable. If the server is
    already running it will respond with an acknowledge.
      If there is no acknowledgement, the client will get it's message back
    as a User_Message_Acknowledge (19) message. It should then try to
    start the server using the -R token and again broadcast the OpenSession
    message, this time with format 1. If again the message is not
    acknowledged, the session failed. The client should delete the data
    file it created and tidy up.
      In the case that all is well, the server will have acknowledged the
    OpenSession message and will also respond by sending a
    Message_OLEOpenSessionAck to inform the client a session is truely
    open. 

    Message_OLEOpenSession (&80E21)
    -------------------------------

    SWI Wimp_SendMessage (&400E7)
    On entry - R0 = User message recorded (18)
             - R1 = ^Block
                 +0 = length of block
                 +4 = not used on entry
                 +8 = not used on entry
                +12 = your_ref (0 for original message)
                +16 = message number (&80E21)
                +20 = 16 byte unique name padded with zeros
                +36 = window handle of display holding file
                +40 = x offset of data in window
                +44 = y offset of data in window
                +48 = format number
                 format = 0 or 1 (edit file)
                  +52 = Session number (24 bit number invented by the client)
                  +56 = file type
                  +60 = full pathname of data, zero terminated
                format = 2 (redit file)
                  +52 = Session number (24 bit number invented by the client)
                format > 2 (reserved for future expansion)
             - R2 = 0 (broadcast)

    On exit  - R0 = corrupted
             Message block is updated:
               R1+4 = task handle of sender (i.e. us, the client)
               R1+8 = my_ref (unique Wimp-generated word > 0)


      Format 0 messages should be sent initially. If a task is running
    which recognises the message it will reply correctly. If the client
    receives the same message back (format 0) because no-one acknowledged
    it, it should attempt to start the server task (specified in the
    OLEServer$ variable). It should then set the format to 1 and broadcast
    the message again. If it receives a format 1 message back
    unacknowledged it knows the server has died in some way and it should
    remove the swap file.
      If a client knows it already has a link to a server, it should not
    attempt to send a format 0 open session message. It can send a format
    2 message which will inform a server that the user has tried to perform
    an OLE action on the same data a second time. This gives those
    applications which allow documents to be closed, but not lost from memory
    (eg ArtWorks) a chance to reopen an edit window on the data. If a
    format 2 message comes back unacknowledged, the server has presumably
    died in the meantime. The client should start from scratch with a
    format 0 message.


    Message_OLEOpenSessionAck (&80E22)
    ----------------------------------

    The server returns the same block as OpenSession but copies my_ref to
    your_ref.


(3) Whenever the server saves data back to file, it sends a OLEFileChanged
    User message to the client (using the task handle passed in
    OLEOpenSession). This message format is as follows

    Message_OLEFileChanged (&80E1E)
    -------------------------------
                 +0 = length of block
                 +4 = task handle of sender
                 +8 = my ref
                +12 = 0
                +16 = message number
                +20 = format number
                  format = 0 then
                   +24 = Session number
                   +28 = full pathname of data, zero terminated
                  format = 1 then
                   +24 = Session number 
                         ie pathname still same as that sent by
                         Message_OLEOpenSession
                         (format used by OLESupport)
                  format > 1 then
                   +24... reserved for future extensions

    Note, the server should not feel it owns the file and thus should not
    attempt to delete the file during emergencies. If the server corrupts
    the file, the client should be capable of working out that the file
    format has been compromised when it receives an OLEFileChanged.
      The server will send a format 1 message when it saved the data to
    the same file. If the data was saved to a different file, it will send
    a format 0 message.
      The client can now read the changed file from disk.

(4) Whenever the server throws data away, through user action it sends a
    User message back to the client informing it that the session has
    been terminated.

    Message_OLECloseSession (&80E23)
    --------------------------------
                 +0 = length of block
                 +4 = task handle of sender
                 +8 = my ref
                +12 = 0
                +16 = message number (&80E23)
                +20 = format number
                  format = 0 then
                    +24 = Session number (-1 means all sessions are closing)
                  format > 0 reserved for future extensions

 ?? Note, the client can send this message to a client or broadcast it to
 ?? all clients when sessions are being closed from the clients end. (ie
 ?? the user is closing the application down or removing one of its
 ?? documents).
      It is unclear what is meant here. A client can send a message to a
    client? Which client and how does it know to which client?  And
    why should it want to? Clients should not interfere with
    eachother. Maybe it should read:
      "Note, the server can send this message to a client or broadcast it
    to all clients when sessions are being closed from the server's end.
    (i.e. the user is closing the server application down or removing one
    ot its documents)."
      Or maybe: "The client can send this message to a server or broadcast
    it when sessions are being closed from the client's end. (i.e. when
    the user is closing the client application down or removing one of
    its documents)."


    This message tells the client that the session has ended and the file
    was not modified any further.

    The client should broadcast this message with the Session number set to
    -1 when it is closing down. The servers that are handling its OLE
    editing sessions then know that these sessions can be abandoned.

    When a document is removed from the client (e.g. a Draw picture is
    deleted from a DTP application document) and there was an OLE session
    for that document, the client should send this message to the server
    with the appropriate Session number filled in. The server can then
    abbandon the edit of this document.


Session numbers & task handles
==============================

  To provide context for OLE sessions a session number and task handle
should be kept by the client and server for each session opened. Session
numbers must be allocated by the client task in a way which makes them
unique for the run time of the program. The client should also keep a copy
of the server's task handle which it will receive via
Message_OLEOpenSessionAck. This way it can inform the server whenever it
closes down.


Messages to be handled by the client
====================================

Message_OLECloseSession (&80E23)
--------------------------------
     +0 = length of block
     +4 = task handle of sender
     +8 = my ref
    +12 = 0
    +16 = message number (&80E23)
    +20 = format number
      format = 0 then
        +24 = Session number (-1 means all sessions are closing)
      format > 0 reserved for future extensions

  The client is told that the session as given by the Session number is
closed (or all sessions for -1). The session should be removed from its
list of open sessions. The file on disk should be removed (if it still
exists).
  The client must check if it knows the task handle of the Server. If not,
it should ignore the message.


Message_OLEFileChanged (&80E1E)
-------------------------------
     +0 = length of block
     +4 = task handle of sender
     +8 = my ref
    +12 = 0
    +16 = message number
    +20 = format number
      format = 0 then
       +24 = Session number
       +28 = full pathname of data, zero terminated
      format = 1 then
       +24 = Session number 
             ie pathname still same as that sent by
             Message_OLEOpenSession
             (format used by OLESupport)
      format > 1 then
       +24... reserved for future extensions
    
  This is what OLE is all about. The client is informed that the file has
been changed by the server. It should read the modified file (from the
original path for format 1, the given path for format 0). The client
presumably may want to display the modified file in its own window.
  Note that this message does not imply that the session is over. The
server may issue more OLEFileChanged messages for this file.


Message_OLEOpenSessionAck (&80E22)
----------------------------------
     +0 = length of block
     +4 = task handle of the sender
     +8 = my_ref
    +12 = your_ref
    +16 = message number (&80E22)
    +20 = 16 byte unique name padded with zeros
    +36 = window handle of display holding file
    +40 = x offset of data in window
    +44 = y offset of data in window
    +48 = format number
     format = 0 or 1 (edit file)
      +52 = Session number
      +56 = file type
      +60 = full pathname of data, zero terminated
    format = 2 (redit file)
      +52 = Session number
    format > 2 (reserved for future expansion)

  This message means we are in bussiness. The server is working on the
document and the client may expect OLEFileChanged messages for it.
  It is a copy of the OLEOpenSession message the client sent to the
server, with the your_ref field filled with the value of the my_ref of the
client's original message. The client should make a note of the task
handle in combination with the Session number. When the client at some
point wishes to drop the document that is being edited by the server, it
can tell the server by sending a OLECloseSession message directly to the
server using the task handle received in this message.


Message_OLEOpenSession (&80E21)
-------------------------------
     +0 = length of block
     +4 = task handle of the sender
     +8 = my_ref
    +12 = 0
    +16 = message number (&80E21)
    +20 = 16 byte unique name padded with zeros
    +36 = window handle of display holding file
    +40 = x offset of data in window
    +44 = y offset of data in window
    +48 = format number
     format = 0 or 1 (edit file)
      +52 = Session number
      +56 = file type
      +60 = full pathname of data, zero terminated
    format = 2 (redit file)
      +52 = Session number
    format > 2 (reserved for future expansion)

  The client receives one of these messages when the broadcast of the
message by the client itself was not acknowledged. It should take further
action to try to get the server to respond.
  If a format 0 message comes back, this means the server is not running.
The client should try to start the server using the value in the -R field
of the environment variable and broadcast a new OLEOpenSession message,
this time with format set to 1.
  If a format 1 message comes back, this means that we tried to start the
server but it either died or does not acknowledge the message (i.e. it
refuses to handle the file for some reason). The client should assume the
session failed and clean up (remove the saved file, remove the session
from its internal list, etc).
  If a format 2 message comes back, the server apparently has died since
the last contact. The client should start a new OLE session from scratch,
i.e. send an OLEOpenSession message with format 0 and continue the same
way as for the original session.



Actions a client should take
============================

Starting a session
------------------
  As described above, when a client wants to start an OLE session, it
should write the file to disk and check for the environment variable. It
should make sure it can handle the messages as described above. It should
generate a Session number and remember it belongs to this particular item
in its internal data. It should then broadcast an OLEOpenSession message.
The handler for the OLEOpenSession message will deal with any problems in
case the server was not running. The other handlers will deal with the
rest of the session.


Discarding a file
-----------------
  When the user takes an action that discards an object for which an OLE
session is in progress, the client should send an OLECloseSession User
message to the server. It should then clean up (remove the file, etc).


Quitting the client
-------------------
  If the client it closing down and it still has sessions open, it should
either send each of the servers it knows about an OLECLoseSession User
message with the Session number set to -1, or broadcast such a message
(recommended). (Note: this implies that servers should pay attention to the
task handle of the sender in OLECloseSession messages it receives, and
only stop editing the documents for that particular client). Actually, the
client need not check if it has sessions open, it can simply broadcast the
message.


