OLE Client Specification: Difference between revisions

From RISC OS
Jump to navigationJump to search
(Created, based on OLEClient.txt)
 
(Wikified)
Line 1: Line 1:
==Overview==
---------------------------------------------------------------------------
$Id: OLEClient.txt 1.11 2009-01-16 14:54:41+01 erikgrnh Exp $
---------------------------------------------------------------------------


OLE or object linking and embedding allows an application to share
Originator - Mike
Purpose - Specification of generic 'OLE' interface and mechanisms
Version - $Revision: 1.11 $
Started - 14th August 1993

$Log: OLEClient.txt $
Revision 1.11 2009-01-16 14:54:41+01 erikgrnh
Corrected some typos. Minor clarifications. Some added comments.
All comments from the author are now in the form "[Note EG: ... ]".

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 with a secondary or server application which can edit that
data and return it. This allows compliant applications to gain
data and return it. This allows compliant applications to gain
features provided by specific graphics or text servers without having
features provided by specific graphics or text servers without having
to re-implement those features.
to re-implement those features.

This documentation defines the message passing protocols necessary for
This documentation defines the message passing protocols necessary for
this kind of data sharing.
this kind of data sharing.




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


A client application (such as Impression) may wish to edit data it is
A client application (such as Impression) may wish to edit data it is
capable of loading and rendering (such as drawfiles). There are two options
capable of loading and rendering (such as drawfiles). There are two options
open for such an application. Either it can provide facilities to edit these
open for such an application. Either it can provide facilities to edit these
Line 44: Line 23:




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


Any application which provides its own file type and is capable of editing
Any application which provides 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
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.
a system variable, outlining the file type it can edit.


The syntax of this variable is as follows
The syntax of this variable is as follows


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

X = 0..9 | A..F
X = 0..9 | A..F
AlphaChar = 0..9 | A..Z | a..z
AlphaChar = 0..9 | A..Z | a..z
Line 61: Line 39:
run = 'run ' or '/'
run = 'run ' or '/'


Spaces must be used as separators.
Spaces must be used as separators.


Typical examples are
Typical examples are


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




Tokens
===Tokens===
------


;-N
-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 16 byte string with all unused bytes zeroed.
:Note the server name should be modelled on the application name such as 'OLESupport' used by the support module or 'StrongED' as used by the StrongED text editor.


;-R
This token specifies a unique name to identify the server in
:This token allows a potential client to Wimp_StartTask ('''run''') 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. Examples:
an OpenSession message. This message is broadcast so it is up to
run <Draw$Dir>
the server who recognises the name to respond. This string can
/<Draw$Dir>
be up to 16 characters long. When passed in messages it should be
specified as a 16 byte string with all unused bytes zeroed.
Note the server name should be modelled 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

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
edit a particular data format and wishes to share the data with a server
in order to do so.
in order to do so.


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


===Checking the environment variable===
(1) The client should check to see if an OLEServer$Type_XXX variable
The client should check to see if an OLEServer$Type_XXX variable
exists for its file type.
exists for its file type.
(If it cannot find such a variable, then the client may wish to
(If it cannot find such a variable, then the client may wish to
use the OLESupport module which simulates the response of a client
use the OLESupport module which simulates the response of a client
for particular file types. See OLESupDoc for information on how to
for particular file types. See OLESupDoc for information on how to
use this module task).
use this module task).
[Note EG: this OLESupDoc is lost in the mists of time. If anyone can
Note EG: this OLESupDoc is lost in the mists of time. If anyone can
supply a copy this would be appreciated.]
supply a copy this would be appreciated.


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

Message_OLEOpenSessionAck to inform the client a session is truely
In the case that all is well, the server will have acknowledged the
open.
OpenSession message and will also respond by sending a
Message_OLEOpenSessionAck to inform the client a session is truely
open.


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

SWI Wimp_SendMessage (&400E7)
SWI Wimp_SendMessage (&400E7)
On entry - R0 = User message recorded (18)
On entry - R0 = User message recorded (18)
Line 152: Line 119:
format > 2 (reserved for future expansion)
format > 2 (reserved for future expansion)
- R2 = 0 (broadcast)
- R2 = 0 (broadcast)

On exit - R0 = corrupted
On exit - R0 = corrupted
Message block is updated:
Message block is updated:
Line 159: Line 126:




Format 0 messages should be sent initially. If a task is running
Format 0 messages should be sent initially. If a task is running
which recognises the message it will reply correctly. If the client
which recognises the message it will reply correctly. If the client
receives the same message back (format 0) because no-one acknowledged
receives the same message back (format 0) because no-one acknowledged
it, it should attempt to start the server task (specified in the
it, it should attempt to start the server task (specified in the
OLEServer$ variable). It should then set the format to 1 and broadcast
OLEServer$ variable). It should then set the format to 1 and broadcast
the message again. If it receives a format 1 message back
the message again. If it receives a format 1 message back
unacknowledged it knows the server has died in some way and it should
unacknowledged it knows the server has died in some way and it should
remove the data file.
remove the data file.
[Note EG: The original document says "send the same message off again
Note EG: The original document says "send the same message off again
to the task". This suggests sending the message to the specific task
to the task". This suggests sending the message to the specific task
handle of the server you just started. You can probably use the task
handle of the server you just started. You can probably use the task
handle returned by Wimp_StartTask.]
handle returned by Wimp_StartTask.
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.


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)
Message_OLEOpenSessionAck (&80E22)
----------------------------------
----------------------------------

The server returns the same block as OpenSession but copies my_ref (+8)
The server returns the same block as OpenSession but copies my_ref (+8)
to your_ref (+12). This message tells the client that a session was
to your_ref (+12).
This message tells the client that a session was
opened successfully and may expect Message_OLEFileChanged messages.
opened successfully and may expect Message_OLEFileChanged messages.



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


Message_OLEFileChanged (&80E1E)
Message_OLEFileChanged (&80E1E)
Line 211: Line 181:
+24... reserved for future extensions
+24... reserved for future extensions


Note, the server should not feel it owns the file and thus should not
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
attempt to delete the file during emergencies. If the server corrupts
the file, the client should be capable of working out that the file
the file, the client should be capable of working out that the file
format has been compromised when it receives an OLEFileChanged.
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, providing the new pathname at +28.
The client can now read the changed file from disk.


(4) Whenever the server throws data away through user action, it sends a
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
User message back to the client informing it that the session has
a format 0 message, providing the new pathname at +28.
been terminated.

The client can now read the changed file from disk.

===Closing the session===
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)
Message_OLECloseSession (&80E23)
Line 236: Line 209:
format > 0 reserved for future extensions
format > 0 reserved for future extensions


?? Note, the client can send this message to a client or broadcast it to
''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
all clients when sessions are being closed from the clients end. (ie
?? the user is closing the application down or removing one of its
the user is closing the application down or removing one of its
?? documents).
documents).''


[Note EG:
Note EG:
It is unclear what is meant here. A client can send a message to a
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
client? Which client and how does it know to which client? And
why should it want to? Clients should not interfere with
why should it want to? Clients should not interfere with
each other. Maybe it should read:
each other. Maybe it should read:
"Note, the server can send this message to a client or broadcast it
"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.
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
(i.e. the user is closing the server application down or removing one
ot its documents)."
of its documents)."
Or maybe: "The client can send this message to a server or broadcast
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
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
the user is closing the client application down or removing one of
its documents)."
its documents)."
This last interpretation is the most likely and was used to write the
This last interpretation is the most likely and was used to write the
paragraphs below. Note that servers should then watch for this message
paragraphs below. Note that servers should then watch for this message
too.
too.
]


This message tells the client that the session has ended and the file
This message tells the client that the session has ended and the file
was not modified any further. It should remove the file and drop this
was not modified any further. It should remove the file and drop this
session from its list.
session from its list.


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


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




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


To provide context for OLE sessions a session number and task handle
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
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
numbers must be allocated by the client task in a way which makes them
Line 285: Line 256:
closes down.
closes down.


[Note EG: The text so far was a modified version of the original OLESpec.txt
file, focussing on the client side and adding some extra information. All
that follows below is original work by me.]


==Messages to be handled by the client==


Note EG: I am a bit hazy on the message protocol. In the list below some
Messages to be handled by the client
entries for my ref (+8) and your ref (+12) may be given as zero, when they
====================================
in fact hold a sensible value


===OLECloseSession===
[Note EG: I am a bit hazy on the message protocol. In the list below some
Message_OLECloseSession (&80E23)
entries for my ref (+8) and your ref (+12) may be given as zero, when they
--------------------------------
in fact hold a sensible value]
+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


This message is sent by a server when it wants to close a session
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

This message is sent by a server when it wants to close a session
(probably because the user has finished editing the object) or when it is
(probably because the user has finished editing the object) or when it is
shutting down, in which case all its sessions should be closed.
shutting down, in which case all its sessions should be closed.

The client must check if it knows the task handle of the Server as
The client must check if it knows the task handle of the Server as
given in the message, and has open sessions associated with it. If not,
given in the message, and has open sessions associated with it. If not,
it should ignore the message.
it should ignore the message.

For the given session number the client should remove the file on disk
For the given session number the client should remove the file on disk
(if it still exists), and remove the session from its list of active sessions.
(if it still exists), and remove the session from its list of active sessions.
If the session number was -1, it should do so for all open sessions which
If the session number was -1, it should do so for all open sessions which
were handled by the server identified by the given task handle.
were handled by the server identified by the given task handle.


===OLEFileChanged===
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 (saved to a different file) then
+24 = Session number
+28 = full pathname of data, zero terminated
format = 1 (saved to the same file) then
+24 = Session number
(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
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 (saved to a different file) then
+24 = Session number
+28 = full pathname of data, zero terminated
format = 1 (saved to the same file) then
+24 = Session number
(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
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
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.
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
Note that this message does not imply that the session is over. The
server may issue more OLEFileChanged messages for this file.
server may issue more OLEFileChanged messages for this file.


===OLEOpenSessionAck===
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 (re-edit file)
+52 = Session number
format > 2 (reserved for future expansion)


This message means we are in business. The server is working on the
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 (re-edit file)
+52 = Session number
format > 2 (reserved for future expansion)

This message means we are in business. The server is working on the
document and the client may expect OLEFileChanged messages for it.
document and the client may expect OLEFileChanged messages for it.

It is a copy of the OLEOpenSession message the client sent to the
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
server, with the your_ref field filled with the value of the my_ref of the
client's original message.
client's original message.

The client should make a note of the task handle in combination with
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
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
document that is being edited by the server, it can tell the server by
Line 379: Line 351:
Message_OLECloseSession.
Message_OLECloseSession.


===OLEOpenSession===
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 (re-edit file)
+52 = Session number
format > 2 (reserved for future expansion)


The client receives one of these messages as a type 19 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 (re-edit file)
+52 = Session number
format > 2 (reserved for future expansion)

The client receives one of these messages as a type 19 message
(User_Message_Acknownledge) when the broadcast of the message by the
(User_Message_Acknownledge) when the broadcast of the message by the
client itself was not acknowledged. It should take further action to
client itself was not acknowledged. It should take further action to
try to get the server to respond.
try to get the server to respond.

If a format 0 message comes back, this means the server is not running.
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
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,
of the environment variable and broadcast a new OLEOpenSession message,
this time with format set to 1.
this time with format set to 1.

If a format 1 message comes back, this means that we tried to start the
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
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
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
session failed and clean up (remove the saved file, remove the session
from its internal list, etc).
from its internal list, etc).

If a format 2 message comes back, the server apparently has died since
If a format 2 message comes back, the server apparently has died since
the last contact. The client should clean up the old session and start a
the last contact. The client should clean up the old session and start a
new OLE session from scratch, i.e. send an OLEOpenSession message with
new OLE session from scratch, i.e. send an OLEOpenSession message with
format 0 and continue the same way as for the original session.
format 0 and continue the same way as for the original session.


Note that this message may also come by due to a broadcast by another
Note that this message may also come by due to a broadcast by another
client who is looking for a server. In that case it will be a type 17
client who is looking for a server. In that case it will be a type 17
(User_Message) or, more likely, type 18 (User_Message_Recorded) message.
(User_Message) or, more likely, type 18 (User_Message_Recorded) message.
Line 424: Line 399:




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


Starting a session
===Starting a session===
As described above, when a client wants to start an OLE session, it
------------------
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 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
should make sure it can handle the messages as described above. It should
Line 439: Line 412:
rest of the session.
rest of the session.


===Discarding a file===

When the user takes an action that discards an object for which an OLE
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
session is in progress, the client should send an OLECloseSession User
message to the server. It should then clean up (remove the file, etc).
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
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
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
message with the Session number set to -1, or broadcast such a message

Revision as of 16:07, 24 January 2009

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 re-implement those features.

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 two 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 engage 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 provides 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::HardDisk4.$.Apps.!StrongED


Tokens

-N
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 16 byte string with all unused bytes zeroed.
Note the server name should be modelled on the application name such as 'OLESupport' used by the support module or 'StrongED' as used by the StrongED text editor.
-R
This token allows a potential client to Wimp_StartTask (run) 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. Examples:
run <Draw$Dir>
/<Draw$Dir>


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

Checking the environment variable

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).

Note EG: this OLESupDoc is lost in the mists of time. If anyone can
supply a copy this would be appreciated.

Start the session

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 = the 16 byte unique name from the -N tag, 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 the data file, zero terminated
                format = 2 (re-edit 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 data file.

Note EG: The original document says "send the same message off again
to the task". This suggests sending the message to the specific task
handle of the server you just started. You can probably use the task
handle returned by Wimp_StartTask.

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 (+8)
   to your_ref (+12).

This message tells the client that a session was opened successfully and may expect Message_OLEFileChanged messages.

The data has changed

Whenever the server saves data back to file, it sends an 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 (saved to a different file) then
                  +24 = Session number
                  +28 = full pathname of data, zero terminated
                 format = 1 (saved to the same file) then
                  +24 = Session number
                        (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, providing the new pathname at +28.

The client can now read the changed file from disk.

Closing the session

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).

Note EG:
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
each other. 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
of 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 last interpretation is the most likely and was used to write the
paragraphs below. Note that servers should then watch for this message
too.

This message tells the client that the session has ended and the file was not modified any further. It should remove the file and drop this session from its list.

When a client is closing down, it should broadcast this message with the Session number set to -1. 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 abandon 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

Note EG: I am a bit hazy on the message protocol. In the list below some
entries for my ref (+8) and your ref (+12) may be given as zero, when they
in fact hold a sensible value

OLECloseSession

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

This message is sent by a server when it wants to close a session (probably because the user has finished editing the object) or when it is shutting down, in which case all its sessions should be closed.

The client must check if it knows the task handle of the Server as given in the message, and has open sessions associated with it. If not, it should ignore the message.

For the given session number the client should remove the file on disk (if it still exists), and remove the session from its list of active sessions. If the session number was -1, it should do so for all open sessions which were handled by the server identified by the given task handle.

OLEFileChanged

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 (saved to a different file) then
       +24 = Session number
       +28 = full pathname of data, zero terminated
      format = 1 (saved to the same file) then
       +24 = Session number
             (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.

OLEOpenSessionAck

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 (re-edit file)
      +52 = Session number
    format > 2 (reserved for future expansion)

This message means we are in business. 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. Also, the server is identified by its task handle in all the messages that it sends to clients, such as Message_OLECloseSession.

OLEOpenSession

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 (re-edit file)
      +52 = Session number
     format > 2 (reserved for future expansion) 

The client receives one of these messages as a type 19 message (User_Message_Acknownledge) 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 clean up the old session and 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.

Note that this message may also come by due to a broadcast by another client who is looking for a server. In that case it will be a type 17 (User_Message) or, more likely, type 18 (User_Message_Recorded) message. These should be ignored by the client.


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 User_Message_Recorded (type 18) 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.