Saving and retrieving an OLE client
An OLE container may be designed to produce documents that consist of native data and a variety of OLE objects from third-party applications such as Microsoft Word or Excel. This type of container often persists into a file (perhaps along with its own native data) the data content (or a link to it) of its contained OLE objects. At some later time, it reconstructs the document, both native data and contained OLE object data, from the same file.
A file that supports the storage of both native data and OLE object data is sometimes called a compound file. The OleFile class supports this kind of compound-document storage requirement.
An OleFile works seamlessly with an OleClient in the storage and retrieval of its contained OLE object's data. An OleFile can store multiple OLE clients and, hence, it requires that each one be given a unique name when put into the file. OLE files also allow arbitrary application data to be stored with the OleClient in the file. These attributes of application data are stored in the OleFile under the same name as the OLE object they are associated with. Finally, an OleFile permits one global, unnamed set of application data attributes to be stored in the file.
Saving an OLE client
Given a fully qualified path name string, an OleFile can create and open a compound file for storage through its create: class method. Once opened, an OLE object can be stored using the saveWidget:named: instance method. For example, all the embedded or linked OLE objects in an application can be saved using:
saveWidgetsTo: filepath
"Save the applications data to an OleFile specified by the filepath String."
| file widgets |
(file := OleFile create: filePath) == nil
ifTrue: [^false].
widgets := self mainWindow oleWidgets.
widgets do: [:widget |
file saveWidget: widget named: widget name].
file close
Once an OleFile is created, all OleClient widgets in the application are obtained from the OleMainWindow through its oleWidgets method. This example assumes that when each OleClient widget is created, it is given a unique name which it uses as the unique OleFile storage name.
Note:
An OleFile must be closed with its close method before any OLE object data is committed to the file.
Retrieving an OLE client
An OleFile can be opened, through its open: class method, on an existing file as long as the file was originally created as an OleFile. If it was not, the open: fails. An OLE object's data is retrieved from an OleFile into an existing OleClient widget. The storageNames instance method of OleFile can be used to obtain all the storage names from the file so that the OleClient widgets can be created with the same names they were saved under. Given the storage names, each OleClient can be restored from the OleFile using its restoreWidget:named: instance method. For example, the OLE objects saved in the above example can be restored using:
restoreWidgetsFrom: filePath
"Restore the widgets from the file named by the filePath String."
| file names client |
(file := OleFile open: filePath) == nil ifTrue: [^false].
names := file storageNames.
names do: [:name |
client := composite
createOleClient: name
argBlock: nil.
client
mappedWhenManaged: false;
manageChild.
file restoreWidget: client named: name.
client mappedWhenManaged: true].
file close.
In this example, the OleClient widgets are created with default size and position. The following section describes saving additional attributes of the widgets in the file.
Saving and restoring data attributes
An arbitrary, named data set can also be stored in an OleFile. This permits, for example, data attributes of an OleClient to be stored in the file under the same name as the OleClient. The data set to be saved must be contained in a ByteArray, which can be filled in a variety of ways, including by using the Swapper tool. The OleFile instance method saveAttributes:named: saves a ByteArray of data to the file. For example, the saveWidgetTo: method above can be enhanced to save each widget's position and size:
saveWidgetsTo: filepath
"Save the applications data to an OleFile specified by the filepath String."
| file widgets data |
fileName := filepath.
(file := OleFile create: fileName) == nil
ifTrue: [^false].
widgets := self mainWindow oleWidgets.
data := ByteArray new: 16.
widgets do: [:widget |
data
int32At: 0 put: widget x;
int32At: 4 put: widget y;
int32At: 8 put: widget width;
int32At: 12 put: widget height;
file
saveWidget: widget named: widget name;
saveAttributes: data named: widget name].
file close
Similarly, named data attributes can be restored from an OleFile through the use of the restoreAttributesNamed: method, which answers a new ByteArray containing the saved data. Hence, the example method restoreWidgetsFrom: can be rewritten as:
restoreWidgetsFrom: filePath
"Restore the widgets from the file named by the filePath String."
| file names client data |
(file := OleFile open: filePath) == nil ifTrue: [^false].
names := file storageNames.
names do: [:name |
data := file restoreAttributesNamed: name.
client := composite
createOleClient: name
argBlock: [:w |
w
x: data int32At: 0;
y: data int32At: 4;
width: data int32At: 8;
height: data int32At: 12].
client
mappedWhenManaged: false;
manageChild.
file restoreWidget: client named: name.
client mappedWhenManaged: true].
file close.
Additional methods of OleFile can be used to save and restore unnamed data sets to a file. The methods, which also work with byte arrays, are saveAttributes: and restoreAttributes.
Note:
For numeric data, it is often simpler to use ByteArray accessors (such as, int32At: and int32At:put:) rather than the Swapper tool to fill byte arrays for use with an OleFile.