asked about. In general, it is easier just to consider all the properties. In
any case, if the Compare() method
returns S_OK, then you can be sure that no property has changed.
As the user navigates the tab control, the system will activate each window
as it is first shown to the user. The Properties Component will call CreatePropertyPage() as necessary to indicate to your code that
you need to create the specific window to show. You will know which window to
create based on the property page number passed in.
If the user clicks the Apply button on the properties dialog, the
Properties Component will call the Apply() method. This implies a global action that
indicates you should update the object representation such that all properties are taken into account[36].
During the Apply() processing, it is a good time to Discard()
and Push() a new set of (current) properties on the
stack, as previously discussed:
pIGProperties
-> Discard();
pIGProperties
-> Push();
This supports the proper implementation of the Cancel action.
When the user clicks the Ok or Cancel button, the properties dialog
will be dispatched and the property settings session is (almost) over. Your
code will receive the call to AfterAllPropertyPages(), with a parameter indicating whether the user
pressed Ok, or Cancel. If the user clicked Ok, you simply need to Discard()
twice, if they cancelled, call Pop() twice, then, update your windows controls in
your object to reflect the now current values of the properties[37].
Finally, the GSystem Properties Component will call the DestroyPropertyPage() method, again, passing the page #, once for each page defined, giving
you the opportunity to free up the resources used by the property page
window(s). Note you do not have to create and destroy these windows in this
process. If you like, you may have had them already created before the process
starts, then, in CreatePropertyPage() you
would switch the parent of that window, and in DestroyPropertyPage(), switch the parent back to one of your own object’s or application’s
windows.
There is one final detail that may optionally occur after all property
pages have been dispatched.
There is a system defined interface called the IPropertyNotifySink
interface that is used to notify containers that one or more properties in an
object have changed. This is a “sink” interface which means that a container
implements it and the object calls the methods. Much like the GSystem
Properties Component calls the methods on the IGPropertyPageClient interface
that your object (the sink) provides to that component.
When a container instantiates an object, for example, the one you are
writing, it, the container, may request of your object for an instance of the
IConnectionPointContainer interface. This is a way for the container to find
out if the object has the ability to call methods on “outgoing” interfaces, or,
if the object is capable of calling methods on interfaces that will be provided
by the container[38]. If you are
actively[39]
implementing event interfaces in your object, you will be able to detect when
the container is asking for a “connection point” for the IPropertyNotifySink
interface.
When the container ultimately provides your object with an actual instance
of this interface, you can pass the interface to the GSystem Properties
Component. This will give the Properties Component the information it needs to
tell the container, in turn, that properties have changed when the user has
dispatched the property pages.
Even though the implementation of events and outgoing interfaces is
very complex, you don’t need to forgo this ability if you don’t have control
over the parts of your object where this is implemented.
There is a simple interface called IQuickActivate which, if you or your
development environment implement (and which you can hook into), which will
receive a pointer to an IPropertyNotifySink interface as soon as your object is
created[40].
During the execution of the QuickActivate() method on this interface, pass the
IPropertyNotifySink interface pointer on to the GSystem Properties Component:
HRESULT Function::QuickActivate(
QACONTAINER* qaContainer,
QACONTROL* qaControl)
{
.
.
.
if ( qaContainer -> pPropertyNotifySink )
iProperties ->
ConnectPropertyNotifySink(
qaContainer -> pPropertyNotifySink,
&qaControl -> dwPropNotifyCookie);
.
.
Which will give the Properties Component the information it needs to,
for example, notify Visual Basic that properties have changed after the user
has exercised the properties dialog(s) that you have implemented.
The EditProperties() and AddPropertyPage() methods of the GSystem Properties Component
fully support the properties editing process for any object that supports the ISpecifyPropertyPages interface. In
general, this is the vast majority of COM/ActiveX objects. Any object which
provides property pages must
implement this interface[41].
This means that you can easily provide the property pages of other
objects to the user of your object or application as if you implemented those
property pages yourself.
Further, you can mix these property pages amongst your own just as if
you developed these “external” objects, integrating them completely within your
system.
As an example, consider the property pages for the windows common
controls, such as a ListView control. Such a control might have as many as 10
separate pages that control every detail about the appearance and operation of
the control. Typically, you as developer only see these property pages within
the development environment you are using to place these controls within your
application.
Now, using the GSystem Properties Control, you can show these same
“design-time” property pages to users of your application or object! At the
same time, you can place these property pages directly beside your own, and of
other objects, such that the entire integrated package is presented to your
user at once.
All that is required to achieve this result is that you call the AddPropertyPage() method on the GSystem Properties Component. Note that you can call
this as many times as you’d like and that each time you call it, you don’t just
add a single “property page”, you add an entire object[42]
and all of the property pages that it will implement, to the ultimate
“set” of property pages that will be shown to the user. If some of those
objects support the IGPropertyPageClient interface, then the system will use
that interface during the processing of those
objects, however, this makes no difference to the GSystem Properties Component;
it handles any object that supports IspecifyPropertyPages – a Microsoft defined
interface required of objects implementing property pages.
Whenever you’re user is ready to see property pages, you can start the
process by calling the EditProperties() method on the GSystem Properties Comonent.
pIGProperties
-> EditProperties(
hwndParent,strTitle,NULL);
Where the hwndParent
argument is the window handle of what will be the parent object of the property
settings dialog that will be shown. When you pass NULL as the third argument,
you are telling the system to edit the properties of the object(s) previously
added through the AddPropertyPage() method.
If the call to EditProperties() passes a specific object[43]
in the third parameter, then the system will raise the property settings
dialogs of that object, as long as it
supports ISpecifyPropertyPages as discussed previously.
This means that you
can present to the user any object’s, including the system common controls,
such as Tree-Views and List-Views, properties dialogs.
This capability is
typically only available to developers of the application or object using the
embedded object. Presenting these tools to your users and, on top of that,
remembering the settings the user provided across runs of your application[44]
is a truly powerful example of seamless COM integration.
A time consuming task in windows development
is the manipulation of the contents of windows “controls” on user interface
components. Specifically, setting the text of controls and retrieving the
user’s changes in these controls and making the appropriate changes within the
application.
The GSystem Properties Control assists in
these tasks by supplying a rich set of methods (on both the IGProperties and
the IGProperty interfaces) that “shortcut” the processing path between the data
in the system and the display and manipulation of that data in the windows
controls.
To use these features, you call the methods
on the Property objects that you have created using the GSystem Properties
Component. There are two important “directions” of action inherent in these
methods; “Setting” the contents of the windows controls with the property value
and “Getting” the property values from the windows controls.
These methods are available in two different
places, directly from the GSystem Properties Component, as well as from each of
the property objects that the component created. The difference being that you must use the name of the property
when calling the methods from the main component so that it may locate the particular
property you want to use. Further, the first letter of the method name
implemented through the main component is capitalized, whereas with the
Property object, it is not.
The remaining discussion in this section is
more reference oriented in nature because there is no specific “process” which
would encompass the use of these techniques. Therefore, the following describes
each of these methods in detail. In this material, the pIGProperties
variable is a pointer to an IGProperties interface while the pIGProperty
variable points to a IGProperty interface. You may have an environment in which
you create objects and can reference their properties with dot syntax, in which
case, you would, of course, replace the
“->” operator with “.”.
These methods on both the IGProperty and
IGProperties interface are intended to assist you in moving the values of the
property to and from the windows and/or controls in your system.
In particular, you don’t need are not dealing
with the actual “value” of the property through these methods. You are passing
a window handle to the methods and letting the updating of that window or
property happen within the method. You don’t need to, for example, retrieve the
value of a property, write that onto an intermediate string, and use that
string to update the display in a window. All of this is handled through a
single call to one of the methods described here.
These methods start with either “set” or
“get”. This should not be confused with the “get_” or “put_” in the “values”
methods. It may help to keep the following in mind:
For example, if you have an edit control on a
dialog window and that control’s id number is 5100, when the user changes the
text in that control you would call:
pIGProperty -> getWindowItemValue(hwndDialog,5100);
This means “get” the value of the property
from the control whose id is 5100 in the dialog represented hwndDialog.
You must be aware of the difference between
hwndDialog and the window handle of the actual control itself. Note that some
event handlers that you use in generated MFC C++ code may receive the actual
window handle of the specific control[45]
that is being manipulated by the window. This is in contrast to the above call
which would be passing the parent window
of that window handle.
If you know this to be the case, simply call:
pIGProperty -> getWindowValue(hwndControl)
passing the window handle of the control that
contains the text you want to use to update the property’s value[46]. If
you have debugging for the property enabled, the system will notify you when
you have passed an invalid window handle to any of these methods. However, the
system has no way to determine if you are passing the handle of the correct
window. If you pass a window handle that belongs to an entirely different
control or window, the GSystem Properties Component will faithfully set or
retrieve the value from that window.
Note that the descriptions of the methods on
the IGProperties interface (the default interface for the GSystem Properties
Component) are not specifically given here. This is because these methods are
exactly the same with the exception that they each have an additional argument,
the name of the property, as the first argument of the method. Also, the first
letter of the method name is capitalized. Thus, any description of the Property
level interface method will have an associated Properties Component level
method as in this example:
IGProperty* pIGProperty_FileName;
.
.
pIGProperty_FileName->
getWindowText(hwndWindow);
is equivelant to:
pIGProperties -> GetWindowText(“file
name”,hwndWindow);
where, at some point prior to the second form
of the call, the GSystem Properties Component had been used to create a
property with the name “file name”. While, at some point prior to the first
form, the variable pIGProperty_FileName was given a value, probably during the
creation of the property through the Properties Component.
Here are the methods used to assist in
managing the relationship between controls and properties.
getWindowValue(long hwndControl)
getWindowItemValue(long hwndDialog,
long idControl)
setWindowValue(long hwndControl)
setWindowItemValue(long hwndDialog,
long idControl)
Note: To prevent clutter, the remaining
descriptions will omit the “..Item..”
entries. Simply remember that these are identical, except that the window
handle argument represents a parent window, and an additional long parameter
represents the ID of the specific child window of interes.t
As described above, these methods work with
properties that have some logical representation in text[47],
i.e., so they can be shown in a window control, typically an edit box. Note,
however, that any control that displays text can be used with these methods.
This includes edit boxes as well as static text labels. Note that the “text” of
a dialog window itself is usually that which displays in the title bar, if
anything. Even this text can be used as a property, of course, the user isn’t
able to directly manipulate that text.
setWindowEnabled(long hwndControl)
These methods can be used to enable or
disable the associated controls. In particular, if the value of the property
can be represented as TRUE (has a binary representation of non-zero), then the
window or control is enabled, otherwise, it is disabled.
setWindowComboBoxSelection(long hwndControl)
getWindowComboBoxSelection(long hwndControl)
setWindowComboBoxList(long hwndControl)
getWindowComboBoxList(long hwndControl)
These methods support the use of Combo Boxes
(aka DropDown Lists) as controls in your windows. You must populate the combo boxes
with values pertinent to their context, you can do this by calling the setWindowValue() or,
setWindowComboBoxList(),
method on an array property with the handle of a combo box control. Once this
has been done, you can use the properties to set which selection will be made
and after the user has made a selection, to set the value of the appropriate
property based on that selection.
Again, you “set” the state of the control,
and “get” the value of the property. Therefore, when you call the setWindowCombo…
method, as an example, the GSystem Properties Component will use the current value of the property and set
the text in the combo box to that value. If you have debugging enabled (see
above) and if the appropriate value
is not in the combo box, a message to this effect will be generated and shown.
The following methods are exactly like the
“ComboBox” methods except that they work on a “ListBox” control.
setWindowListBoxSelection(long hwndControl)
getWindowListBoxSelection(long hwndControl)
setWindowListBoxList(long hwndControl)
getWindowListBoxList(long hwndControl)
These methods are for check boxes and radio
button controls. You pass the appropriate window to the “set” methods and the
current value of the property (TRUE or non-zero, or FALSE or zero) determines
the state of the check box.
setWindowChecked(long hwndControl)
getWindowChecked(long hwndControl)
The following methods are useful with “Array”
properties. Here the “..Item..”
version is also shown, it takes a SafeArray argument representing the IDs of
the windows associated with the array of window handles.
getWindowArrayValues(
SAFEARRAY(long)*
hwndControls)
getWindowItemArrayValues(
SAFEARRAY(long)*
hwndDialogs,
SAFEARRAY(long)* idControls)
setWindowArrayValues(
SAFEARRAY(long)* hwndControls)
setWindowItemArrayValues(
SAFEARRAY(long)* hwndDialogs,
SAFEARRAY(long)* idControls)
To clarify, these arguments are pointers to
SafeArrays containing longs. The “hwnd…”
arrays contain the window handles of the controls, in the case of the “..Item..”
methods, they contain the window handles of the parent windows and the idControls
argument contains the child window IDs.
These
methods are intended for use with properties that have an array type. When you
call these methods, you must pass an array of window handles. Even if all of
the controls are on the same window, you must pass an array of the window
handles.
The point of these methods is to manipulate
the contents of many controls at once given the value of a single property
which represents an array.
When you need to
communicate with the GSystem Properties Component, you use the interfaces
described in this section. These interfaces are dual automation interfaces
which means you can use them in one of two ways, as dictated by the needs of
your software and/or environment.
You can access the
GSystem Properties Component using early or late binding. In particular, you
can have your development environment learn of, and use, the capabilities of the
component when your application or object is being compiled and linked; this is
early binding. Alternatively, for environments that don’t utilize a concept of
“compiling” and linking, you may need to use “late” binding which allows your
application or object to discover and use the capabilities of the GSystem
Properties Component at run time.
In some development
environments, the use of some of the methods described herein is very much like
the syntax if the method were an actual property, or variable, on the
interface. For example, in Visual Basic you may have the two expressions:
dim n as
integer
n =
property.Value
property.Value
= n
In reality, however,
there are two distinct “methods” on the IGProperty interface. In environments
that don’t support the translation, you need to know the actual method name and
calling syntax. Therefore, when you see the description of the get_ and set_
methods in the following discussion, you will know that you may be able to use
the method as outlined above, i.e., as a variable on the “object” containing
the interface.
The convention used
in this document to represent these methods is, by example:
{put |
get}_longValue({long | long *} theValue)
In the above, there
are two methods represented, one is:
put_longValue(long
theValue)
The other is:
get_longValue(long*
theValue)
And, in Visual Basic
and other enviroments, which understand how to translate the calls into a more
natural look, the syntax is:
property.longValue
= theValue
or,
theValue =
property.longValue
In this case,
“property” will be an instance of the Property object, which is an instance of
the object class that the GSystem Properties Component maintains to form the
set of properties.
Our syntax will
describe both methods at once. In particular, the “{ }“s with the “|” inside
denote that one or the other of the items to either side of the “|” is to be
included (of course, spaces would be removed where they cause syntax errors).
Also, that if more than one of these appear in a single construct, then the
same numerical order of selection that was made in the first group must be made
in every other one as well.
When you see the
argument is passing a pointer, you are generally expecting that the object will
“return” a value to you (the caller) through this method[48].
Visual Basic will deal with this appropriately if you use the standard
assignment syntax as described above.
Note that if no put_
method is documented, then that “variable” may not appear on the left side of
an ‘=’ statement. Assignment is not possible with such an item.
Every property that
is added to the GSystem Properties Component for management has a unique copy
of this interface you can use to manipulate the property.
There are four
categories of things you can do with each property, these are:
The methods on this interface begin with a
lower case letter. This is purposefully done to distinguish them from methods
in the IGProperties interface[49].
Since the latter generally deals things at a higher level, while this interface
is dealing with single items, i.e., each property.
get_binaryData(BYTE** pBinaryData);
This method is primarily intended for
internal use by the GSystem Properties Component. However, if you want to
retrieve and store the internal binary representation of the property for some
reason, you may use this method. You may do this, for example, to quickly
compare the value of a complex property, such as an array property at different
points in time. Note that the pointer
returned is a pointer to memory space within the GSystem Properties Component,
if you want to hold on to this binary representation, you should allocate
memory in your own memory space (note the get_size()
method will tell you how much you need[50])
and copy the data returned from this method into it.
copyTo(IGProperty*
pIGProperty_destination)
You can copy the value of one property to
another by providing the IGProperty interface to the “destination” property.
The source property is the property that has provided the IGProperty interface
that you use to call this method.
{put | get}_debuggingEnabled(
{BOOL | BOOL*} setEnabled)
During your early stages in development with
the GSystem Properties Component, it pays to turn debugging on so that the
Component can notify you, by displaying a message box, if you make an error in
your use of the Component. For example, it is easy to pass an invalid window
handle to the window support methods and you want to be notified about this
during your development work so that you can correct the problem. The system
will return S_OK in most cases if debugging is turned on (after displaying it’s
information) so that you’re software under test may continue. However, with
debugging off these methods generally return E_FAIL which will cause a Visual Basic application to terminate.
directAccess(void* nativeStorage,
long sizeOfStorage)
This
method allows you to allow the property to access memory within
your object or application.[51] In
C or C++ environments, you can pass the address of allocated storage (or a
member variable) so that the property can use that storage directly as the
location of the property’s value. This is specifically used so that you won’t
have to make the value setting and retrieving calls (described later) to keep
the property’s value up to date. In particular, each time you set the value of
a variable in your system, if that variable’s address had also been passed to
the associated property through this method, then that property is always up to
date. Likewise, you can set the property’s value and the variable is
automatically updated.
On the other hand, in environments where this
kind of memory access is not supported, you can use the properties generated by
the GSystem Properties Component directly as if they were variables. Providing
the same level of convenience as this method provides.
{put |
get}_encodedText(
{ BSTR | BSTR*} encodedText)
You can retrieve a non-binary representation
of the property using the above method. An “encoded” text string is a hexadecimal
representation of the entire property that can be saved by your application
such that you can recreate the value of the property at any point in the
future. This would be done by passing that encoded text string back in put_encodedText(). Of course, persistence of the properties is
the job of the GSystem Properties Component so you don’t need to do this, however, you might have a side reason for it, such
as, for example, storing the property in a “text” database field.
{put |
get}_isDirty({ BOOL | BOOL*} isDirty)
You can ask the property if it’s value has
changed since it was created, since you last called this method, or since it
was last written to a storage medium.
{put |
get}_name({ BSTR | BSTR *} name)
Sets the “name” of the property. Generally, when
the property is created through the Add()
method on the IGProperties interface, this name would have been specified
there. There may be times, however, that you want to retrieve the properties’
name. A BSTR is the formal name for the OLE safe string type. This is the same
as the String type in Visual Basic.
get_size(long* pSize)
To determine how much storage the property
uses. Note that this method can be used on the right side of an ‘=’ in
environments that support this. In VB:
dim s as integer
s = property.size
However, there is no way to use this method
as if you were assigning a value to it, which is true of any method that does
not have an associated “put_…”. This method would typically have no use
outside of the internals of the GSystem Properties Component, however, access
to the property’s binary data is available if some client wants it, therefore,
this method’s usage would typically couple with the get_binaryData()
method.
{put |
get}_type (
{ PropertyType | PropertyType *}type)
The property type determines the underlying
data that is stored with the property, i.e., it is roughly equivalent to
variable types in many environments. Typically, a property will “learn” of its
type whenever a value is assigned to that property for the first time, i.e., it
is not usually necessary to specify the type. However, there are certain times
when you must explicitly set the type, for example, when the property is a
TYPE_OBJECT_STORAGE_ARRAY, it is necessary to call put_type() to
indicate this to the system. At other times, you will probably call the get_type()
method to determine the type of the property if you needed to know this for
some reason.
get_variantType(VARTYPE *vtype)
When you set the value of the property using
the put_value() method, your development environment will
“assemble” some VARIANT to pass as the argument to that method. If you’d like
to see the actual type of the passed VARIANT, use this method. As an example,
if you pass a literal integer from Visual Basic, VB will, in turn, create either
a VT_I2, or a VT_I4 variable for the property, this method allows you to see
what VB did in this case.
These
methods are used to set and retrieve the “values” of the property. They are
covered in alphabetical order.
{put | get}_arrayValue(
{ SAFEARRAY(VARIANT)| SAFEARRAY(VARIANT)* }
theArray)
These
methods use SAFEARRAY’s to maintain the value of the property. Used in
conjunction with list and combo-boxes, this type of property can be very
useful. Note that the SAFEARRAY passed in is copied into the property and that
it may be an array of any valid VARIANT type, including other SAFEARRAY’s.
However, VT_UNKNOWN and VT_DISPATCH are not useful in this context.[52]
Four
methods pertinent to array properties are described here as they are relevant
only to array properties.
{put |
get}_arrayIndex (
{ long | long* } theIndex)
Sets
which element of the array is “current”. This “property of the property” is
saved and restored along with the array property. This way, not only are the
contents of a list box saved, so is its selection.
{put |
get}_arrayElement (
long elementIndex,
{ VARIANT* | VARIANT ** } theValue)
Adds,
replaces, or removes one of the members in the array. Passing a VARIANT value (
or retrieving a VARIANT) and one of the values from the following table:
|
ARRAY_INDEX_REMOVE |
-4 |
Take the element out of the
array (the element passed is the index of the element) |
|
ARRAY_INDEX_ADD |
-3 |
Add the element to the end
of the array |
|
ARRAY_INDEX_FIRST |
-2 |
Replace the first element
or add if no elements |
|
ARRAY_INDEX_LAST |
-1 |
Replace the last element,
or add if no elements |
|
Any other value |
|
Replace the element at that
position, if the value supplied is within the range. |
get_arrayElementCount(
long *elementCount)
Lets
you know how many elements are in the array.
ClearArray()
Removes
all elements from the array.
{put | get}_binaryValue(long
countBytes,
{ BYTE* | BYTE ** } theValue)
You
can store any type of binary data in a property. The GSystem Properties
Component makes no attempt to validate the data, it only requires that the
property be a TYPE_BINARY property if you use this method. Using this type of
property, you can save any structure or object as long as you can get its size
and address[53] to supply to this method. The property’s
data is ultimately written to a system supplied storage mechanism and there is
no restriction on what type of data that may be. However, note that if your
binary data contains pointers to other data, you must have some mechanism for
recovering that “other” data after your property has been “restored” from a
storage. In particular, the pointers will not be valid after your object
(containing the property) is restored. Perhaps you have “other” properties
utilized to account for this situation, or, you can use the
TYPE_OBJECT_STORAGE_ARRAY property if applicable.
Note
that the TYPE_BINARY property is very convenient for structures defined either
by windows or by your application or object. For example, the SIZE structure
defined in windows can be passed to a property of this type so that the size of
the object’s main window can be stored with the properties. In a certain sense,
the binary property is a “catch all” for other types of data not represented in
the other types. The term, however, should not be considered to denigrate the
value of the property type as it is quite useful for any type of data.
Understanding and using the directAccess() method in conjunction with this type of
property is very efficient.
{put | get}_boolValue(
{BOOL | BOOL *}
boolValue)
To
set or retrieve the value of a property that contains TRUE or FALSE.
{put | get}_doubleValue(
{double | double* }
doubleValue)
This
method sets or retrieves the double value of the property.
{put | get}_longValue(
{long | long *} longValue)
Again,
these are the same as the associated “double” properties. Here, the stored
values are long integers (32 bits).
{put | get}_stringValue(
{BSTR | BSTR*
} bstrValue)
These
methods manipulate the property when it is an OLE compatible BSTR. These are a
special representation of character data that is safe for use across disparate
environments, for example Visual Basic and a C/C++ object.
{put | get}_szValue(char
*szString)
To
set or retrieve a C style null terminated “string” property, use the above
methods. In the GSystem Properties Component, these strings are an array of
ascii characters, the last one of which is a value of ‘0’. In other
environments that use OLE strings (BSTR strings) use the put(get_)_stringValue() methods instead.
Note
the get_… and put_… methods both pass a pointer to
char. The caller must pass a character array that has enough space to receive
the string when using the “get_…” method. Again, use the get_size() method if you need to know the size of this string.
These
methods are the subject of Part
VI of this manual. Please refer to page 66 for more information.
This interface is
the primary interface used for managing the group
of properties as a whole. However, many of the methods can be used to “get
at” particular properties. For example, by using the name of the property that
was used when the property was created. This is intended as an easy way to
access one of the properties in the set without having to maintain a pointer to
each property’s interface.
The interface
contains groupings of methods:
These methods
provide general control over the GSystem Properties Component. Where the
IGProperty method names start with a lower case letter, these methods (with the
exception of the get_ and put_ methods) start with an upper case name. This
convention is intended to help differentiate the methods where the
functionality is very similar. In particular, methods that are like named in
these two interfaces will deal with a particular
property in the IGProperty interface, where, in the IGProperties interface,
the method’s first argument is the name of the property and that method will
internally find and reference the appropriate property.
Here are the
miscellaneous methods on this interface.
CopyTo(IGProperties*
pIGProperties_destination)
This method is used
to copy the entire set of properties (and their values) into another instance
of the GSystem Properties Component. You can load the properties of one object
into those of another object, typically of the same general “type” of object.
Only like named properties are copied using the target object’s IGProperties
interface. In other words, each property in the source (defined as the object
which owns the IGProperties interface that this method is called on) is copied
into the destination only if a property with the same name exists in the
destination.
get_Count(long* theCount)
This method returns
the number of properties currently being maintained by the Component.
{put |
get}_DebuggingEnabled(
{BOOL | BOOL *} setEnabled)
You can enable the
display of informative messages during the early stages of your work with the
GSystem Properties Component. This assists in working out minor errors such as
the misspelling of property names or the passing of an invalid window handle.
When you set this value, all of the existing properties are affected, as well
as all properties created by the component subsequent to this call. If you want
to turn off the debugging capability of just one property, you can call put_debuggingEnabled(FALSE) on that property’s IGProperty interface.
DirectAccess(BSTR
propertyName,
void* accessableAddress,
long sizeOfMemory)
This method allows
you to specify that a property use the address of a particular variable or
allocated space in your object or application. Please see the equivalent
description of this method on page 74.
{get |
put}_FileAllowedExtensions(
{BSTR | BSTR* }fileExtensions)
This property
dictates what will appear in the standard system File Open (or Save) dialog box
in the drop-down list that indicates the allowed extensions of the file to
open.
{get | put}_FileName({BSTR |
BSTR* }fileName)
If the system were
asked to store the properties at any given time, this property will specify
what the name of that storage file will be. If this value is not specified when
an application calls Save(), the system will prompt the user for the file name.
get | put}_FileType({BSTR |
BSTR* }fileType)
In conjunction with FileAllowedExtensions, indicates text that will appear in the System File Save-As or File
Open dialog boxes.
get | put}_FileType({BSTR |
BSTR* }fileType)
Also in the system
File Open, Save, dialogs, the text that appears in the title-bar of those
dialogs.
GetPropertyInterfaces(
long* countInterfaces,
IGProperty*** theInterfaces)
This method allows
you to retrieve the interfaces to all of the properties in the set of
properties currently maintained by the GSystem Properties Component. Note that
you pass the address of a long integer that will, upon return, contain the
number of actual properties being maintained. Also note that the “triple”
pointer to the returned interfaces may be thought of as a returned “array” of
pointers to these interfaces. The GSystem Properties Component allocates all of
the necessary space for this array. It is the caller’s responsibility to call CoTaskMemFree() on this returned array in order to free the memory.
Here is example code
calling this interface:
long
cntOthers;
IGProperty**
ppIGProperty_Array;
pIGProperties
-> GetPropertyInterfaces(
&cntOthers,
&ppIGProperty_Array);
for ( int
k = 0; k < cntOthers; k++ )
{
IGProperty* pDestination =
ppIGProperty_Array[k];
pDestination -> . . .
.
}
CoTaskMemFree(ppIGProperty_Array);
Often times a
container will need a unique identifier for your object. The GSystem Properties
Component will handle the call to supply this value. However, the Component
needs to have an appropriate value to provide the container. This method is
provided to allow you, the user of the GSystem Properties Component, the
opportunity to provide this information to the GSystem Properties Component.
In particular, you
should call this method soon after you have created the Properties Component or
after your application starts if you have statically included the Component in
your application.
If you are building
an object, you should pass a pointer to the CLSID of your object to this
method. For controls based on the MFC class COleControl, you can call the GetClassID()
method to retrieve this value. If you
don’t have access to a CLSID[54]
identifier for your application or object, you can make one with the “guidgen”
utility.
Note: This
method does not need to be called if you
supply the IGPropertiesClient interface as described on page 44. This is because that interface has a GetClassID()
method that the GSystem Properties Component can call when and if it needs this
information.
New()
This method will
initialize the set of properties managed by the GSystem Properties Component.
This will overwrite the current state of all of the properties. If debugging is
turned on and the current set of properties are “dirty”, i.e., need saved, a
warning message to this effect is displayed. You should call Save()
before New() if your intent is not to overwrite the properties.
LoadFile(BOOL*
pWasSuccessful)
This method will cause
the storage saved in the file whose name is the FileName properties of the GSystem Properties
Component. This method returns FALSE if the file could not be opened, TRUE
otherwise.
Open(BSTR* pStrFileName)
This method prompts
the user for a file to open. Note that the properties on the GSystem Properties
Component specify the details for the Open File dialog shown to the user, for
example, the allowed extensions for the files. The method returns the name of
the file selected by the user. If the user cancels or the file cannot be
opened, the system returns an empty string.
OpenFile(BSTR strFileName)
This method opens
the existing file with the name given, at the same time, it sets the fileName
property to reflect the “current” active file.
Note that this method
will also cause the current set of properties to be overwritten. Again, with
debugging enabled, a message to the effect that unsaved properties are
overwritten will be issued. However, the method will overwrite the properties
in any case.
Save()
Causes the current
set of properties to be saved in the “current” file. Note that the GSystem
Properties Component has properties that indicate the path and file name of the
current file. These are the FileName property. Remember that calling OpenFile(strFileName) will also reset the value of these properties to reflect the file
named in that call.
SaveAs(BSTR* pStrFileName)
This method will
prompt the user for a file name and then save the current set of properties to
that file. As with the Open() method, the system returns the file name
selected.
SaveTo(BSTR strFileName)
The final method in this set save the properties in file whose name is
provided. This method also sets the “current” active file by setting the fileName
property of the GSystem Properties Component.
Add(BSTR name,
[optional]
IGProperty** ppIGProperty)
This method adds a
new property into the collection of properties that the GSystem Properties
Component manages. The BSTR argument is the standard OLE/COM string argument.
The second argument is a pointer to a pointer to an IGProperty interface. If
this parameter is supplied (i.e., non-NULL), the method will return a pointer
to the interface on the property that is created.
Include(IGProperty*
pIGProperty)
Used to “Add” a property created either
directly through COM or from other source, for example, an additional GSystem
Properties Component. The receiving Properties Component will AddRef() the
interface passed and will Release() it
when the Properties Component is completely released.
Property(BSTR
propertyname,IGProperty** pProp)
This method is used to return a property
which has the given property name. Before returning the IGProperty interface,
if found, the system AddRef()s
it, therefore, you need to Release() it
when you are done with it.
Remove(BSTR propertyname)
Simply removes the property from the set of
properties maintained by the system.
These methods are used to allow your object
or application to participate in the “process” of saving and retrieving data to
or from a storage.
More specifically, these methods are
generally used during execution of methods in the IGPropertiesClient interface
(discussed below) that you write for the purpose of integrating into the
persistence process. This process is discussed in general terms starting on
page 44.
Advise(IGPropertiesClient *pIGPropertiesClient)
This method provides the Component with an
implementation of the IGPropertiesClient interface that it can use to
communicate with your object or application[55].
Note that this communication is for the purposes of the persistence processes
as described on page 44, not for the property
pages implementation. When you use the property pages features of the GSystem
Properties Component, the Component will ask your software for an
implementation of IGPropertiesClient that it can use, you don’t need to call Advise().
PutHWNDPersistence(hwndPersistence,
hwndInit,
hwndLoad,
hwndSavePrep);
As described on page 41, this method is used to
provide simple access to your code in the persistence process. You supply the
window handles of command button controls that are implemented in the passed
parent window handle. At certain points in the persistence process, the GSystem
Properties Component will send the window the appropriate command message,
which will cause the command handlers to get called by the system.
You may call this method for each window that
you want to be notified of the actions in the persistence process. If you do
not implement one of the commands shown, pass zero for the handle of that
command window.
IsDirty()
This method is called to ask your object if
the properties are dirty (need to be saved). Return S_OK for TRUE (the object
needs saving) or S_FALSE for FALSE. This is in response to the system asking
this question of the GSystem Properties Component. The process of saving data
is not guaranteed just because TRUE is returned; that decision is up to the
client or container that initiated the request.
These methods are used to assist your object
or application in managing the windows displayed to the user for the purpose of
“editing” the properties.
As previously mentioned, there are two ways
to accomplish property page support with the GSystem Properties Component.
Methods that do not depend on which of the two ways you select to implement
property pages are described first.
EditProperties(HWND hwndOwner,
BSTR tabText,
IUnknown* forObject)
This method is used to initiate the edit
properties process. Typically it is called when your application, or the client
of your object, requests the OLEIVERB_PROPERTIES verb be performed through the
IOleObject interface. You can call this method at any time to cause the GSystem
Properties Component to create and display the property pages on behalf of your
object (or application). Note that it doesn’t matter whether you have
implemented the easier method, or the more complex method of property pages
integration. This method will initiate the process for whatever method you have
chosen.
In fact, if you had chosen to keep the MFC,
or any other, implementation of property pages, this method will still bring up
those property pages.
Note also that you pass the IUnknown
interface pointer for the object whose properties you want to edit. This can be
any object on the users’ system whatsoever. In other words, it does not matter
how or who implemented the property pages for a given object; as long as that
object has been created and you have a pointer to an IUnknown interface on the
object, you can get the edit properties dialogs to display for the property[56].
These methods are used to manipulate the
“stack” of properties. The GSystem Properties Component allows you to “push”
and “pop” the entire property set and to compare the “current” set of
properties with the set of properties on the top of the stack (last pushed).
This is most convenient for determining the extent to which properties have
changed during, for example, the properties editing process.
Push()
This method is used to place the entire set
of properties on the “stack”. This is a method by which you can save the entire
property set for later restoration. Each time you Push() the
properties on to the stack, a copy of every property is saved such that you can
restore the set of properties with a simple Pop() of
the stack.
The number of times you can Push() the
stack is limited only by available memory.
Pop()
When you Pop() the
stack, you restore all of the properties to the state they had when you last Push()-ed
the stack. Note that you can’t Pop()
more times than you call Push(). If
you have debugging enabled, attempting extra Pop()s
will generate a message. The action is otherwise benign.
Discard()
Similar to Pop()
except the properties do not revert to the values from when they were last Push()-ed.
For example, if the user accepts the current state of the properties, you can
go ahead and discard the top of the stack as it won’t be needed for
restoration.
Compare()
Does a binary “compare” between the current
set of properties and those on the top of the stack (last Push()-ed).
Returns S_OK if all of the properties are identical, or S_FALSE otherwise. You
can use this method to determine if any of the current set of properties have
changed since they were last Push()-ed
onto the stack.
PutHWNDPropertyPage(BSTR
displayName,
HWND hwndProperties,
HWND hwndStart,
HWND hwndOK,
HWND hwndApply,
HWND hwndCancel);
RemoveHWNDPropertyPage(HWND
hwndProperties);
The mechanics of the simpler property page
implementation method are discussed in detail on page 53. In summary, the
display name is the text displayed on the tab for this particular window. The
hwndProperties argument is the handle to the dialog or window that will be
shown. And the four remaing HWND values are the control window handles of
command buttons that are handled by the window procedure for the given (parent)
window handle.
The RemoveHWNDPropertyPage()
method is used to take the given window back out of the list of windows that
will be shown when property pages are next shown. Note that the list of
property pages shown can change dynamically, each page showing a different
subset of the entire set of properties, for example.
AdvisePropertyPageClient(
IGPropertyPageClient*
pIGPropertyPageClient)
This method provides the Properties Component
with access to your application or object through the interface you have
implemented. For complete details of the IGPropertiesClient interface, please
see the next section. Note that this call will AddRef() the
passed in interface.
To clear the list of property pages
implemented, call this method with a NULL value. That indicates to the system
that it should Release() all of the pointers to either ISpecifyPropertyPages or
IGPropertyPageClient that it is holding. Once this is done, you can add a
different set of objects into the list of objects providing property pages.
Note also that it is necessary for the passed
in interface to implement IGPropertyPageClient, however, that implementation
may return 0 property pages when asked through the interface’s GetPropertyPagesInfo()
method. This is useful if, for example, your object doesn’t really implement
properties or property pages, however, it manages one or more embedded objects
that do have property pages.
AddPropertyPage(IUnknown* pIUnknownObject)
This method notifies the GSystem Properties
Component that you are using the more complex and feature rich process in order
to edit properties.
The IUnknown interface pointer should be a
valid IUnknown interface to any object that implements either the IGPropertiesClient interface, or the
ISpecifyPropertyPages[57]
interface. It is important that this can be virtually any object that implements one of these interfaces (or both). It
does not necessarily have to be your particular object which owns the
IGProperties interface through which you have called this method.
Note that this method will attempt to get one
of the two interfaces from the object, starting with the IGPropertyPageClient
interface, and that doing so successfully will cause 1 AddRef() on
the object.
ConnectPropertyNotifySink(
IPropertyNotifySink
*pINotify,
DWORD dwCookie)
This method notifies the GSystem Properties
Component that your container would like to be notified when a property
changes. If you implement or override an instance of the IOleObject, you may get passed a valid pointer to an
IPropertyNotifySink[58]
interface. If you pass this interface on to the IGProperties interface, the
latter component will notify your container (the implementor of the notify sink
interface) whenever the user has edited properties through the property pages
dialogs. This technique requires your object to implement connection points
(event interfaces), but for you to have enough control over the implementation
be able to call the following method at the appropriate time.
FindConnectionPoint(
REFIID riid IConnectionPoint
**);
If you do pass on a container’s
IPropertyNotifySink to the GSystem Properties Component, as in the previous
method description, you also need to pass a request of your object to make the
connection on to the GSystem Properties Component as well.
In particular, if you support connection
points, you implement IConnectionPointContainer. On this interface, you may
receive a call to connect (through the FindConnectionPoint()
method) to an IPropertyNotifySink interface. When you receive this call, simply
delegate the call to the GSystem Properties Component.
Here is an implementation of this technique
by an object that supports a connection to an event interface.
STDMETHODIMP
Function::FindConnectionPoint(
REFIID riid,IConnectionPoint **ppCP)
{
*ppCP = NULL;
if ( riid == DIID_IGSFunctionEvents )
return connectionPoint.QueryInterface(
IID_IConnectionPoint,(void **)ppCP);
return iProperties ->
FindConnectionPoint(riid,ppCP);
}
In the example, if the requested identifier
of the sink interface is not one the method knows about, then it just passes
the request on to the GSystem Properties Component, through a cached
IGProperties interface represented by the variable iProperties;
These methods are the subject of Part VI of this manual. Please
refer to page 66 for more information
It bears repeating, however, that the methods
on this interface do have the additional (first) argument which specifies the
name of the property. The system will simply forward the appropriate call to
the IGProperty interface of the property with the given name, if found.
This interface
represents the points in your object or application that will be participating
in the persistence process that the GSystem Properties Component manages on
your behalf.
Don’t forget, this
is an interface that you write. The GSystem Properties Component simply
specifies what the methods should be, not how, why, or if they are ultimately
implemented.
The “Client” in this
interface is the GSystem Properties Component itself. If you have supplied the
capability, the Properties Component will be calling methods on this interface.
Again, these methods
are used by the Properties Component in support of the process of saving and
restoring data from the system storage.
These methods are
discussed in detail in Part IV starting on page 44. The methods are repeated here in brief form
for clarity.
SavePrep()
This method will be
called just before writing the properties to the storage. This gives your
object the opportunity to update the values of its properties or to perform any
preparatory processing.
InitNew()
When the Properties
Component is notified by the container or client (of your object) that a new
instance has been created, it will in turn notify your code by calling this
method. Generally, this is a good time to set all of your properties to their
default values. Once this has been don, you can call the Loaded()
method to update the system windows/controls with the new values of the
properties.
Loaded()
This method is called after the GSystem Properties has read all of the
properties (that belong to the object which instantiated the Properties Component)
from the binary storage. At this point, your properties have the same state as
the last time the user saved your object. You can take this opportunity to
re-paint your object to reflect the new state of these properties.
GetClassID(BYTE *)
When the container
or client needs to have the GUID of the object being saved, the GSystem
Properties Component will call this method so that your code can supply this
value.
For a thorough discussion of these issues, see the description of the SetClassID()
method in the section starting on page 82.
This interface
consists of methods (again, that you write) which are involved in the processes
that occur when the user edits properties using property pages. These methods
were discussed in detail starting on page 56. The material here will be more summary
information.
AfterAllPropertyPages(BOOL userCanceled)
This method is
called when the user has finished the properties settings session.
Specifically, it is called before the dialog containing all of the property
pages closes. It is called only once regardless of the number of property pages
used. The userCanceled argument will be TRUE if the user pressed the “Cancel” key
to close the dialog, FALSE otherwise.
Apply()
This method is
called when the user presses the “Apply” button on the property settings
dialog.
BeforeAllPropertyPages()
This method is
called once before all of the property pages are shown. You can take advantage
of knowing this method is called only once per properties setting session. For
example, by Push()ing all of the properties as discussed previously.
CreatePropertyPage(
long
pageNumber,
HWND
hwndParent,
RECT
rectSize,
BOOL isModal,
HWND
* pHwndPropertyPage)
When the system is
ready for you to create your property page (the one given the appropriate #,
see the GetPropertyPagesInfo() method), it will call this method. Note that it
will pass the window handle of what will become the parent of your property
page window, the recommended size, and whether it is a modal window, as in a
modal dialog, for example. You use whatever mechanism you have to create this
window, using the passed window handle as it’s parent. Alternatively, you can
simply “set” the parent window handle of an already created window.
DestroyPropertyPage(long pageNumber)
The opposite of the
above method. Simply notifies you that the system no long needs the window.
Note that if you simply set the parent of a window in the previous method, it
is important to set it back in this method. This is because that parent will
most likely be destroyed soon after this call has been made.
GetPropertyPagesInfo(
long*
cntPages,
SAFEARRAY(BSTR)* pageNames,
SAFEARRAY(BSTR)* helpDirs,
SAFEARRAY(long)* pageSizes)
When the system
needs to know how many pages you are going to supply, it will call this method.
You return the number of pages in the cntPages parameter and you Re-Dimension
(if you have more than 1) the SAFEARRAYs and place the required information in
each of these.
A detailed example
of this method is shown on page 57.
Help(BSTR bstrHelpFile)
If, in your
implementation of GetPropertyPagesInfo(), you supplied a help file name for any of
the property pages, this method is called when the user click’s Help while that
page is active in the dialog. If you return S_FALSE from this method, the
GSystem Properties Component will attempt to launch the help file using the
old-style WinHelp. If you want handle the display of help yourself, return
S_OK.
IsPageDirty(long
pageNumber,BOOL *isDirty)
From time to time,
the Properties Component will ask your object if the properties represented by
a particular window have changed. The Properties Component uses this
information to know whether the Apply button should be enabled. You should set
the passed parameter accordingly.
Use the Compare()
method to determine if properties have changed.
# glossary
# About the GSystems Properties Component
# Deployed at the application level
# Deployed at the component level
# What is the GSystem Properties Component
# What is persistence
# other useful features
# record-oriented application
[1] The user doesn’t have to know about “files”. You could present some list to the user that “represents” files and which your application would know how to associate with the correct file. This list could itself be maintained by an application level property that is an array of strings.
[2] This is a powerful feature; using the GSystem Properties Component, you can now combine property pages from several objects and present these to the user as one property frame. That is, one dialog containing the property pages from distinct, and separately developed, ActiveX/COM objects.
# instantiation
[3] The GSystem Properties Control does not care if it is instantiated as an ActiveX control or not, i.e., it does not require that it have some visual representation on a form or parent container and is built to not rely upon the existence of this kind of environment.
[4] If you implement IGPropertiesClient, you might as well put the code to create the properties in the InitNew() method on that interface. You could even put the code that creates the GSystem Properties Component there as long as you only create that object once during the instance of your object (or application).
[5] This is a C/C++ example, VB and other environments typically have the last argument not appear in the call but rather be “assigned” to, such as
DIM property_interface as GSystemProperty
Set property_interface = GProperties.Add(“property name”)
[6] Value is the default property of each property object. This means that in VB, you can assign the data the property will maintain with the statement:
property = “the Value”
which is the same as calling property.put_value(“the Value”) from C.
[7] If any, remember that in certain environments, you can use the properties as the data itself, i.e., you don’t have to maintain separate variables to swap in and out of the properties.
[8] Which must be a TYPE_ARRAY property, though it can be an array of any “type” of variables, either VARIANT or any scalar type.
[9] As with all of the property methods, there will be an “equivelent” method on the GSystem Properties Component itself. In this method, the only difference is that the name of the property is passed in the first argument, and that the first letter of the method name is capitalized. That technique causes the master component to find the appropriate property and call the associated method on that property, relieving your code from the necessity of keeping a reference to each property.
[10] Note that the VB Dim controls() as long statement will do this for you. In C/C++ environments you will have to create and populate a SAFEARRAY object of the necessary size.
[11] Note this is something you must do every time your window is created since the window handles themselves can 1) not be persisted and 2) will have different values each time the window is created.
[12] Which, for this example is referred to by
the name GProperties. When the object is placed on a VB form, it was probably
called GSystemProperties1.
[13] For various internal reasons, the system
generates a name for the property.
[14] In fact, the default “property” of each
GSystemProperty object is its value. This means that the value of the property
is what gets set when a variable (or expression) representing the property is
on the left side of an equals sign. Because of this you must mentally make the
distinction between the use of the “Set” statement and the assignment statement
such that the reference to the property object does not get inadvertently
changed.
[15] Though you must at least provide the stub of
all the subroutines.
[16] Even though the IGPropertiesClient interface
is defined for the GSystem Properties Component to call its methods, it is
often very convenient, and perfectly legal, for code that you write to call
these methods. In fact, you may find the structure and functionality of this interface
suits many aspects of your application, such as calling InitNew()
as a natural way to “reset” the state of the system quickly. The functionality
within this interface is typically present in most applications, it is
therefore convenient to place your code here for the benefit of both the entire
application and for the GSystem Properties Component’s ability to enhance the
application.
[17] The Save() and LoadFile() methods both use the FileName
property of the GSystem Properties Component as the destination and source
files respectively. For LoadFile(), the file must exist or the method will not
succeed and will return a non-zero value.
[18] The LoadFile() method and the “Open” methods
will pop-up a warning if the current state of any properties is dirty, that is
the properties will be lost if they are overwritten. No action is taken by the
GSystem Properties Component in such a case, only a warning that processing
logic allowed this to happen, which may be perfectly acceptable in the context
of your system.
[19] Strictly speaking, the sample application
uses an ActiveX object which embeds the GSystem Function Generator Sample. That ActiveX Object is also provided,
the FunctionContainer sample.
[20] The COleControl base class is providing
persistence services by implementing these interfaces. However, the GSystem
Properties Component provides a much tighter integration of your code with the processes involved with persistence and
properties. If you want to take advantage of this higher functionality, you
must inhibit the COleControl’s implementation as described. Note that this does
not break your COM object in any way, it simply provides you more control over
its functionality.
[21] Or, with an environment like Visual Basic,
you code your logic into the “Click()” event on the associated command buttons
and Visual Basic will route the request from the GSystem Properties Control to
that code as appropriate.
[22] A “signature” denotes the types of each
argument to the method as well as the type of the return value.
[23] This definition may come from a type
library, from the “Components” information
maintained by Visual Basic, or from a header file accompanying a COM
object that may be expecting this interface.
[24] Or, it will send a message to the hwndInit
window passed in a previous call to PutHwndPersistence().
[25] Or, it will send a message to the hwndSavePrep
window passed in a previous call to PutHWNDPersistence().
[26] Remembering that the sequence of properties
or objects that the GSystem Properties Component expects to encounter when
Loading the data must be the same
sequence as when that data was saved. For this reason, you cannot arbitrarily
add properties at run-time and a single type of property is needed that can act
as a “place-holder” for many objects at once.
[27] Or, it will send a message to the hwndLoaded
window passed in a previous call to PutHwndPersistence().
[28] You can edit properties in sub-objects of
your object this way. However, you can also combine
the property pages of all objects you are maintaining in your system using the
techniques provided by the GSystem Properties Component’s implementation of
Property Pages.
[29] You don’t have to implement this interface,
the Properties Component does it for you. However, it may help to understand
how this interface works to most effectively use the GSystem Properties
component.
[30] Keep in mind that the actual properties
dialog is built and displayed by the system. The dialog that you create, whose
window you pass to PutHWNDPropertyPage(), is displayed as a child of the system generated properties dialog.
[31] Remember that you can supply any number of
windows to the GSystem Properties Component if you would like to have different
“sub-sets” of properties.
[32] It is actually not required that the passed
in object support IGPropertyPageClient. Significantly, if this object supports
ISpecifyPropertyPages, which any object must do in order to present property
pages, then this object’s property pages will be included along with your own,
if any, in the set of property pages; seamlessly added to yours as if you
implemented them. See page 63 for more information.
[33] Your development environment should know
what this is. In Visual Basic, the argument to the subroutine for the “names”
array will appear as:
…,pageNames() As String,…
You must “ReDim” this array as appropriate before
putting the strings into it.
[34] All of this assumes that your application or
object implements the IGPropertyPageClient interface which it must do in order
to use this property page implementation. If it does not, you may still use the
simpler windows messaging based technique.
[35] The pages are numbered from 1 through the
number of property pages you specified in your implementation of the GetPropertyPagesInfo() method, and are in the order that you placed them in the arrays passed
to that method.
[36] This is the easiest approach. If you want to
break your set of properties into sub-sets, each represented by its own
property window, you may need to avoid using all of the properties when you
draw your object. Keep in mind that, if you are updating properties in your
property window procedures, these values will
have been updated when each respective window was visible, then if you want
to see the effects of “Applying” only the properties that are on the current window, you must somehow
separate out the “other” properties in the representation of your object. Of
course, you can always have more than one instance of the GSystem Properties
Component.
[37] If you implemented IGProperitesClient,
simply call your implementation of Loaded() on that interface.
[38] When an object defines a certain “event”
interface, it is essentially asking a container to implement the interface, and
expects the container to in-turn, ask the object if it is able to call methods
on that interface if it, the container, will agree to implement it.
[39] Meaning that you have control of the pertinent parts of the process in
your object, or, that you can somehow “hook” the process if it is under the
control of MFC or ATL, for example.
[40] If the
container knows about and seeks to use this interface.
[41] In the case of your object, you are allowing
the GSystem Properties Component to do this for you.
[42] Again, any
object that supports ISpecifyPropertyPages
[43] Strictly, the IUnknown interface of an
object.
[44] Using the persistence capabilities of the
GSystem Properties Component, i.e., calling AddObject() to
include “foreign” objects among the properties to persist.
[45] Every control on every window has a window
handle and is itself a window
[46] Note that the “type” of the property does
not have to be a text (TYPE_STRING for this to work. The GSystem Properties
Component will properly format the value from the text in the control if, for
example, the type of the property is TYPE_DATE.
[47] Array properties, however, do have a
property called arrayIndex (put_…, get_arrayIndex) which indicates the current
“active” member of the array, which can be shown in a scalar context.
[48] With some exceptions, usually where passing
an “object” would be more efficient by passing a pointer to an object instead.
[49] Note that certain MFC wizards and perhaps
other tools get confused between the lower case letter on the IGProperty
interface and an exactly named, except with an upper case initial letter,
method on the IGProperties interface. Sometimes, these tools will “think” the
actual name of the method on the latter interface has the lower case initial
letter, probably because of the close proximity in definition of the two
interfaces. There is no effect of this bug except that you may find it
necessary to “go along” with the incorrect assessment by the development tool.
[50] The size information is dynamic, i.e., do
not hold onto a size value returned and use it later, call get_size(), allocate
the storage, call get_binaryData and then copy the data into your allocated
memory, all in sequence.
[51] This is optional. Please see the discussion
of the issues involved on page 15.
[52] Again, the TYPE_OBJECT_STORAGE_ARRAY may be
useful for maintaining other objects.
[53] In this case, the address is not used by the
GSystem Properties Component beyond simply copying this binary data from that
location at the time this method is called. In other words, the Properties
Component allocates its own internal storage to hold this binary data and you
need not be concerned with the issues involved with the directAccess() method.
[54] This is really just a 128bit magic number
that provides a unique identifier for any given object or item that needs one.
[55] Remember that your software implements the
IGPropertiesClient interface.
[56] This does require that the object implement
the ISpecifyPropertyPages interface, which is a standard COM interface expected
to be implemented by all objects, regardless of author or platform, that want
to have the capability of showing property pages.
[57] A Microsoft defined interface that any
object that intends to offer property pages must implement.
[58] A Microsoft defined interface that lets a
container know (because it is implemented by a container) when a contained
object’s properties have changed.


--- layout: post authors: ["Belinda Weaver"] title: "What I Learned in Brisbane" date: 2015-07-07 time: "21:00:00" tags: ["University of Queensland"] ---
Not a single negative was recorded about the people either teaching or helping out at the Brisbane Software Carpentry bootcamp last Thursday and Friday (2-3 July). There were a lot of positive comments though:
The workshop is great with passionate instructors
All the helpers in the room are very helpful and fun
Excellent support from helpers
Instructors readily available to help especially when falling behind or [we] need help understanding codes
Negative comments largely focused on pacing—a 75%/25% split between too fast/too slow, the sound quality (there were microphone issues which made it hard to hear at times especially when lots of people were getting help, which added to the noise), problems with software (surprise, surprise) , and the vagaries of wireless set up and connectivity. Even the room itself got a minus from one attendee for not being bright enough or warm enough (it is the middle of winter in Brisbane).
Despite having helpers on site an hour before the workshop, we still had some attendees with setup issues as the first (Shell) session began on day one. Luckily with six helpers available, plus the instructors not actually teaching, there were enough supporters to get these people sorted while the rest of the class cracked on.
We were lucky with our support numbers—we had six certified instructors attending (one of whom—me—was attending the workshop as a learner as well), plus six helpers, many of them Python experts. For all the instructors, it was their first Software Carpentry workshop since qualifying, so we were keen to discuss what worked/what didn't work so that we can do better in September when our next bootcamp is scheduled.
We had a large number of women both as attendees and as instructors and helpers. Out of 40 attendees, 17 were women—almost half! Four of the six instructors were women.
The workshop was BYO laptop. We had a mixture of operating systems to deal with—about a dozen Windows machines, a few Linux laptops, and the rest Macs. To counter issues with people not being able to download or open programs, we used a DIT4C container (initially set up by Tim Dettrick for ResBaz in Melbourne) to allow people to use Python, the shell, Git and sqlite3 within a Web browser. While this worked well for those using it, there was inevitably confusion at the start of sessions as people worked out which instructions to follow.
The Git session attracted the most positive comments (12) and the fewest negatives (1). What sold people on this was—overwhelmingly—the provision of context. As we learned in instructor training, people need to know why something will be useful before they will invest the energy to learn it. A couple of attendees even wanted more Git, which is a good sign.
Next time, we will aim to teach three things—Shell, Git, and either Python or R—not four. Trying to cover SQL as well was too much for two days, though the SQL session was very positively received. We did receive comments that the "program was too ambitious" and "too much for two days".
Since the workshop ended, four participants (10%) have expressed interest in instructor training, which is great.
Some of the participants had come prior to attending the annual UQ Winter School in Mathematical and Computational Biology, which started on 6 July. We might plan a workshop next year just for those attendees as we had to turn away a large number of Winter School people. Our bootcamp sold out very early, and we ended up with a waitlist of 30 people.
For next time, we need to:
Explain the etherpad more, and use it better.
Point people to the Software Carpentry lessons online, AND to the relevant sections of the etherpad at the start of each session so they can easily catch up if they get lost.
Provide more context at the start of each session.
Recap more—repetition doesn't hurt.
Get a better whiteboard.
Use more diagrams to help visual learners.
Aim to have a second projection screen.
Improve the room set up so everyone is facing forward.
Check that the microphones work, and preferably use mobile mikes.
Make sure we have all the right connection cables for laptop to projector, e.g. HDMI, VGA.
Run everything in the DIT4C container to save on set-up time and to provide consistency BUT help people download the software they will need to use post-bootcamp.
Join up with the Winter School to offer a combined event, if possible.
The Brisbane Team
Back row: - L-R Nick Coghlan, Sam Hames, Caleb Hattingh, Heidi Perrett, Mitch Stanton-Cook, Shaw Innes
Front Row: L-R - Amanda Miotto, Belinda Weaver, Darya Vanichkina, Paula Andrea Martinez, Areej Alsheikh (Absent: Tim Dettrick)
Day 1
Day 2
Lunchtime—people still working hard
Bootcampers, instructors and helpers—end of day 2
Areej Alsheikh at the podium


To help you navigate throughout the VA Web site easily, we have included a map of the high level pages below.
Some of the VA offices that have a presence on our site also offer maps of their sites. Links to these maps are found in the blue stripe on the left side of this page.


Keto Bombs
☰
˟
HOME
SWEET BOMBS
SAVORY BOMBS
CHOCOLATE BOMBS
DAIRY-FREE BOMBS
UNSWEETENED BOMBS
NUT-FREE BOMBS
EDITOR'S FAVORITES
ABOUT
Dairy-Free Keto Bombs
Example


SmartGraph.Dag An implementation of Directed Acyclic Graphs
Contents
-
Introduction
-
Directed Acyclic Graphs
-
The SmartGraph.Dag library
-
SmartGraph.Dag.Algorithm
Introduction
The SmartGraph.Dag library contains classes and algorithms for building and
manipulating Directed Acyclic Graphs (or DAGs).
Directed Acyclic Graphs
A graph, in general, is a container of vertices and edges. A vertex is an object
i.e. whatever you want it to be, and an edge is a tuple of vertices (source,
target) where the order of the items in the tuple does not matter. A DAG is a
type of graph where an edge is an ordered tuple. A DAG thus specifies a set of
relationships on a set of objects. The 'relationship' says that one object is
dependent on another ie the target depends on the source.
SmartGraph.Dag implementation
An interface-based approach to implementation has been used throught the
library. The following interfaces are defined:
-
IDAGObject
- defines a base for all other 'DAGObjects'.
-
IVertex
(derived from IDAGObject) - defines a vertex (or node).
-
IEdge
(derived from IDAGObject) - defines an edge (source, target).
-
IGraph
(derived from IDAGObject) - defines a container of vertices and edges.
-
IGraphFactory - defines a set of methods for creating
IGraph's.
SmartGraph.Dag.Algorithm
The following algorithms have been implemented:
-
DepthFirstSearch
- performs a depth-first-search (or DFS). This means following the out-edges
(from source to target) of vertices.
-
ToplogicalSort
- sorts the vertices of a graph based on the edges. The creates an ordering on
the vertices of the graph based on their inter-dependencies which is a kind of
DFS. The difference is that each node is 'noted' *after* all its children have
been 'noted' and not *before* like in DFS.
-
EquivalenceClasses - sorts vertices of a graph into lists of
vertices. Nodes in the same list have a 'connection' in other words
directedness of edges is not taken into account.


Welcome to the Johnson & Johnson Animal Hospital. This app is intended for staff use only.
To access the app:
Click HereThis app was designed using Apache Isis,™ a framework to let you rapidly develop domain-driven apps in Java. This app has been generated using Isis' SimpleApp archetype, which configures Isis to run a very simple and purposefully minimal application. Access to the UI is provided by the Wicket Viewer, which, as its name suggests, is built on top of Apache Wicket™.
The default user/password is sven/pass


Hey you!
Do you want to have an impact?
Define your own goals.
We take care of your commitment.
Make a Goal.
Bet on yourself.
Commit.
Reaching your goal has never been more fun.


CGRED.CONF
Section: libcgroup Manual (5)Updated: 2009-03-16
Index Return to Main Contents
NAME
cgred.conf - libcgroup configuration fileDESCRIPTION
cgred.conf is cgred service configuration file. In this file there could be defined several internal values. Defining anything else in this file will cause the CGroup Rules Daemon program to fail.-
CONFIG_FILE
specifies the configuration file for cgred service
- LOG_FILE
-
variable specifies the file to which logs will be written
(by default they are not sent to a file but to syslog)
- NODAEMON
-
if it is equal to "--nodamon" then
run cgred in non-daemon mode
- LOG
- define the verbosity of logging. Accepted values are '-v', '-vv', '-q' and '--nolog'.
FILES
- /etc/cgred.conf
- default libcgroup configuration file
-
SEE ALSO
cgrules.conf (5), cgconfig.conf (5)
Index
This document was created by man2html, using the manual pages.
Time: 05:33:59 GMT, December 24, 2015


Package
Class
Tree
Deprecated
Index
Help
PREV NEXT
FRAMES
NO FRAMES
All Classes
B
C
D
G
I
L
R
T
V
B
BOTTOM
- Static variable in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Bottom alignment - string will be alligned at bottom, in relation to the y anchor point
C
CENTER
- Static variable in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Center alignment - string will be horizontally aligned in the centre, in relation to the x anchor point
com.rattat.micro.ui.effects.imagestring
- package com.rattat.micro.ui.effects.imagestring
D
DEFAULT_CHARS
- Static variable in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
A character array holding all of the characters which will be loaded if no characters list is passed to the constructor.
draw(Graphics, String, int, int, int)
- Method in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Render the string onto the Graphics, built from individual character images.
draw(Graphics, int, int, int, int)
- Method in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Render the integer onto the Graphics, built from individual character images.
G
getHeight(String)
- Method in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Get the height of the area that will be drawn when rendering the string
getWidth(String)
- Method in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Get the width of the area that will be drawn when rendering the string
I
ImageStringDrawer
- Class in
com.rattat.micro.ui.effects.imagestring
ImageStringDrawer is used for drawing strings built from a collection of images representing individual characters.
ImageStringDrawer(String, char[])
- Constructor for class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Creates a new instance of ImageStringDrawer
ImageStringDrawer(String)
- Constructor for class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Creates a new instance of ImageStringDrawer
L
LEFT
- Static variable in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Left alignment - string will be horizontally aligned to the left, in relation to the x anchor point
R
RIGHT
- Static variable in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Right alignment - string will be horizontally aligned to the right, in relation to the x anchor point
T
TOP
- Static variable in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Top alignment - string will be alligned at top when rendered, in relation to the y anchor point
V
VCENTER
- Static variable in class com.rattat.micro.ui.effects.imagestring.
ImageStringDrawer
Vertical center alignment - string will be vertically alligned in middle, in relation to the y anchor point
B
C
D
G
I
L
R
T
V
Package
Class
Tree
Deprecated
Index
Help
PREV NEXT
FRAMES
NO FRAMES
All Classes


{%- import 'include/component/table.html' as table -%} {%- import 'include/component/dialog.html' as dialog -%} {%- import 'include/component/datetimepicker.html' as datetimepicker -%}


Haul wind dance the hempen jig blow the man down
Jib pillage ho stern topmast sloop. Jury mast American Main piracy dead men tell no tales run a rig snow. Tackle lass case shot trysail overhaul keel. Sutler snow doubloon list Yellow Jack transom.
Jib pillage ho stern topmast sloop. Jury mast American Main piracy dead men tell no tales run a rig snow. Tackle lass case shot trysail overhaul keel. Sutler snow doubloon list Yellow Jack transom.
Sail ho piracy haul wind red ensign hardtack cable. Swab spirits Barbary Coast strike colors rope's end bowsprit. Driver black spot chandler long clothes bucko cog. Sloop heave down transom strike colors gunwalls barque.
Measured fer yer chains coffer scallywag marooned chandler splice the main brace. Sail ho spanker dance the hempen jig bilge grapple handsomely. Coffer keel swab avast walk the plank chase guns. Barque barkadeer clap of thunder scuttle Barbary Coast wench.
Yo-ho-ho jib chase guns spike lanyard. Draught gangway long boat handsomely topsail.


The cast, all students from Ohio University, is nothing less than electric, oozing chemistry on and off stage. The show is put on by the Lost Flamingo Theatre Company, or LFC, and for some, this is their last time stumbling into the eerie mansion of Frank-N-Furter. For others, it's their first time experiencing the sexual awakening of "Rocky."
"I didn't know anything about 'Rocky' except that you were supposed to dress like a slut, which I did," Abbie Ogilbee, a sophomore who plays Columbia and saw "Rocky" for the very first time last year at The Union, said. "It was great."
The 1975 film "The Rocky Horror Picture Show" follows lovers Brad Majors and Janet Weiss as they navigate a mysterious mansion and its interesting characters. The iconic movie has been adapted into a live show that allows people to express their true selves through song, dance and sexual innuendos.
"Rocky" has been a monumental part of many cast members' lives. It is for Nathan Stanley, who first joined the cast in 2018 and is playing Dr. Everett V. Scott.
"I've always loved the movie, since I was way too young to be watching the movie," Stanley said. "I thought it was really cool, and I was like, 'Why not try out?' Then, I almost didn't try out, and then my friend was coming. She was like, 'Come with me,' so I did, and the rest is history."
Stanley said that the performance is an opportunity for people to feel accepted and celebrate themselves and each other. The show, Stanley said, unexpectedly brings people together in ways they may not have known an hour and 38 minutes ago.
"I would say Rocky is like nothing you've ever seen," Ogilbee said. "It's crazy and it's bloody. And it's really an awakening, you will be horny all night."
Like Stanley and Ogilbee, Makenzie Price, who plays Magenta, said "Rocky" radiates togetherness and, for Price, "Rocky" is the heart of Athens.
"I love performing in general, but there's something about my connection to this role that feels unearthly in a way," Price said.  I've always struggled with femininity and masculinity – specifically, I wanted to be more masculine and this is more feminine for me, but I feel comfortable in it and I never felt that way before. So it was kind of a way of taking back femininity in a way … it felt right for me."
The cast believes "Rocky" is the perfect chance for someone who has never experienced this type of show to express their true selves.
"They (the audience) should just come in open-minded, ready to have fun, and feel whatever sexual feelings that they feel because that's a part of the show," Price said.
Another key factor of "Rocky" is the carrying on of roles until one graduates or decides to leave the production. Janet Weiss, played by Emily Ivory, and Brad Majors, played by Mac Christian, know the feeling of longevity in Rocky. Ivory and Christian, both seniors, have been working together for three years now and have watched themselves grow through the characters.
The show, for Ivory, is intertwined with messages of confidence and comfort.
"I think it gave me … a completely new set of friends, a whole new confidence just in myself and I think that it could probably bring that for anybody who is a part of it," Ivory said.
Christian has continued his role because of the excitement it brings everyone who watches it.
"Well, at the beginning, when I get naked, it's an interesting feeling," Christian said. "But once you get that out of the way and you get the stockings on and the heels on — that's what I love the most about the show, because it's something I would never have done in a million years. Then, I did it here."
The show would not be complete without the ensemble, better known as the "Whorus."
"I decided to join because everyone in the cast is super hot and super cool, and I went to the show last year, and I was super captivated," Jack Wilburn, a sophomore who's in Rocky for the first time as a member of the Whorus this year, said. "Everybody did such an amazing job.
Junior Lily Boulard, the "whoreographer" for "Rocky," senior Emma Ledford-Adkins, the sign and sophomore Erin Bishop, the lips, are all members of the Whorus. Boulard returned this year and took on the role of choreographer because of a love for the show. The show, Boulard said, is a hallmark for queer representation and a staple of Athens' individuality.
Zoe Cranfill | Staff Photographer
Columbia, Abbie Ogilbee, practices her part for Rocky Horror Picture Show LIVE at Bentley Hall on October 18, 2022.
“Our version is done in a way that only 'Rocky' is done”-Lily Boulard
"...You walk in and it's a bar, and then they're playing the movie and then they're acting in front of it and you're like, 'What is this? Is it a movie? Is it a play? Is it a musical?' Who knows," Boulard said. "People are interacting with the audience. It's a very distinct, idiosyncratic show."
Ledford-Adkins said the show is a change of pace from the high-stress, everyday college life that many people at OU experience, and for Bishop, "Rocky" relays the message that even when someone is looking, one should always be themselves.
Thursday, Friday and Saturday are a chance to be surrounded by people who embrace themselves for who they are and encourage others to do the same. It also provides an opportunity to watch the cast perform memorable moments.

Being up on stage is nerve-racking, but the audiences make it worth it. The cast feeds off of the energy the audience gives during the performance. Senior Heylea Allan, who plays Riff Raff, was once a member of the audience but has a role in the show this year.
"I have seen it the two times it's happened in my college career … my partner actually played this role before me, so I took it on," Allan said. "It's like a legacy thing."
Filling the shoes of Dr. Frank-N-Furter this year is junior Quinn Bennett. Through the process of preparing the show for opening night, Bennett, along with the rest of the cast, has felt an array of emotions from stress to excitement.
"I just feel lucky to have been a part of the whole process because everybody here is so great and because the show is so great," Bennett said. "Doing it on the stage … is going to be fun. The audience's energy is what makes the show."
Putting it all together is director Zoe Korns and assistant director Max Levitsky, who are both seniors.
"I love this show," Korns said. "And I love the people involved in it. 'Rocky' is really close to my heart. It's something that I've been a huge fan of for many years of my life and doing it with some of my favorite people and my best friends has been a great experience."
Korns said seeing how the audience will receive the show is what's most anticipated. So much dedication goes into making it the most electrifying event of the fall, and Christian agrees.  "And I think that's probably why it reigns."
The checkered floors of The Union are awaiting a crowd of heels and corsets. "The Rocky Horror Picture Show" will be at The Union from Oct. 20 to Oct. 22. The doors will open at 8 p.m. and costs $8 for those 21 and over and $10 for those under 21.
If there's one thing to leave "Rocky" with, it's, "Don't dream it, be it," Bennett said.


| Vendor Name: | AMEC AMERICAS LIMITED. |
|---|---|
| Reference Number: |<PHONE_NUMBER> |
| Contract Date: | 2015-10-16 |
| Description Of Work: | 423 Engineering Consultants - Other |
| Contract Period: | 2015-10-16 to 2015-12-31 |
| Original Contract Value: | $11,408.48 |
| Contract Value: | $11,408.48 |
| Comments: | This contract was sole-sourced. Architect and Engineering Services (including Landscaping, Interior Layout, and Designing) |


Usage Notes¶
Warning
The software includes a tracking system to report usage statistics and errors.
Users can opt-out using the --notrack
command line argument.
Execution and the BIDS format¶
The ASLPRep workflow takes as principal input the path of the dataset that is to be processed. The ASL BIDS are currently being proposed and in the final stage. We have created a simple way of converting ASL into BIDS
The input dataset is required to be in valid BIDS format, and it must include at least one T1w structural image We highly recommend that you validate your dataset with the free, online BIDS Validator.
The exact command to run ASLRep depends on the Installation method. The common parts of the command follow the BIDS-Apps definition. Example:
aslprep data/bids_root/ out/ participant -w work/
Command-Line Arguments¶
ASLPrep: ASL PREProcessing workflows
usage: aslprep [-h] [--version] [--skip_bids_validation]
[--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]]
[--bids-filter-file PATH] [-t TASK_ID] [--echo-idx ECHO_IDX]
[--nthreads NTHREADS] [--omp-nthreads OMP_NTHREADS]
[--mem_mb MEM_MB] [--low-mem] [--use-plugin USE_PLUGIN]
[--anat-only] [--boilerplate] [--md-only-boilerplate] [-v]
[--ignore {fieldmaps,slicetiming,sbref} [{fieldmaps,slicetiming,sbref} ...]]
[--longitudinal] [--t2s-coreg]
[--output-spaces [OUTPUT_SPACES [OUTPUT_SPACES ...]]]
[--bold2t1w-dof {6,9,12}] [--force-bbr] [--force-no-bbr]
[--medial-surface-nan] [--dummy-scans DUMMY_SCANS]
[--skull-strip-template SKULL_STRIP_TEMPLATE]
[--skull-strip-fixed-seed] [--fmap-bspline] [--fmap-no-demean]
[--use-syn-sdc] [--force-syn] [--fs-license-file PATH]
[--fs-subjects-dir PATH] [--no-submm-recon]
[--cifti-output [{91k,170k}] | --fs-no-reconall] [-w WORK_DIR]
[--clean-workdir] [--resource-monitor] [--reports-only]
[--run-uuid RUN_UUID] [--write-graph] [--stop-on-first-crash]
[--notrack] [--sloppy] [--pcasl]
bids_dir output_dir {participant}
Positional Arguments¶
- bids_dir
the root folder of a BIDS valid dataset (sub-XXXXX folders should be found at the top level in this folder).
- output_dir
the output path for the outcomes of preprocessing and visual reports
- analysis_level
Possible choices: participant
processing stage to be run, only “participant” in the case of aslprep (see BIDS-Apps specification).
Named Arguments¶
- --version
show program’s version number and exit
Options for filtering BIDS queries¶
- --skip_bids_validation, --skip-bids-validation
assume the input dataset is BIDS compliant and skip the validation
- --participant_label, --participant-label
a space delimited list of participant identifiers or a single identifier (the sub- prefix can be removed)
- --bids-filter-file
a JSON file describing custom BIDS input filter using pybids {<suffix>:{<entity>:<filter>,…},…} (https://github.com/bids-standard/pybids/blob/master/bids/layout/config/bids.json)
- -t, --task-id
select a specific task to be processed
- --echo-idx
select a specific echo to be processed in a multiecho series
Options to handle performance¶
- --nthreads, --n_cpus, -n-cpus
maximum number of threads across all processes
- --omp-nthreads
maximum number of threads per-process
- --mem_mb, --mem-mb
upper bound memory limit for ASLPREP processes
- --low-mem
attempt to reduce memory usage (will increase disk usage in working directory)
- --use-plugin
nipype plugin configuration file
- --anat-only
run anatomical workflows only
- --boilerplate
generate boilerplate only
- --md-only-boilerplate
skip generation of HTML and LaTeX formatted citation with pandoc
- -v, --verbose
increases log verbosity for each occurence, debug level is -vvv
Workflow configuration¶
- --ignore
Possible choices: fieldmaps, slicetiming, sbref
ignore selected aspects of the input dataset to disable corresponding parts of the workflow (a space delimited list)
- --longitudinal
treat dataset as longitudinal - may increase runtime
- --t2s-coreg
If provided with multi-echo BOLD dataset, create T2*-map and perform T2*-driven coregistration. When multi-echo data is provided and this option is not enabled, standard EPI-T1 coregistration is performed using the middle echo.
- --output-spaces
Standard and non-standard spaces to resample anatomical and functional images to
- --bold2t1w-dof
Possible choices: 6, 9, 12
Degrees of freedom when registering BOLD to T1w images. 6 degrees (rotation and translation) are used by default.
- --force-bbr
Always use boundary-based registration (no goodness-of-fit checks)
- --force-no-bbr
Do not use boundary-based registration (no goodness-of-fit checks)
- --medial-surface-nan
Replace medial wall values with NaNs on functional GIFTI files. Only performed for GIFTI files mapped to a freesurfer subject (fsaverage or fsnative).
- --dummy-scans
Number of non steady state volumes.
Specific options for ANTs registrations¶
- --skull-strip-template
select a template for skull-stripping with antsBrainExtraction
- --skull-strip-fixed-seed
do not use a random seed for skull-stripping - will ensure run-to-run replicability when used with –omp-nthreads 1
Specific options for handling fieldmaps¶
- --fmap-bspline
fit a B-Spline field using least-squares (experimental)
- --fmap-no-demean
do not remove median (within mask) from fieldmap
Specific options for SyN distortion correction¶
- --use-syn-sdc
EXPERIMENTAL: Use fieldmap-free distortion correction
- --force-syn
EXPERIMENTAL/TEMPORARY: Use SyN correction in addition to fieldmap correction, if available
Specific options for FreeSurfer preprocessing¶
- --fs-license-file
Path to FreeSurfer license key file. Get it (for free) by registering at https://surfer.nmr.mgh.harvard.edu/registration.html
- --fs-subjects-dir
Path to existing FreeSurfer subjects directory to reuse. (default: OUTPUT_DIR/freesurfer)
Surface preprocessing options¶
- --no-submm-recon
disable sub-millimeter (hires) reconstruction
- --cifti-output
Possible choices: 91k, 170k
output preprocessed BOLD as a CIFTI dense timeseries. Optionally, the number of grayordinate can be specified (default is 91k, which equates to 2mm resolution)
- --fs-no-reconall
disable FreeSurfer surface preprocessing.
Other options¶
- -w, --work-dir
path where intermediate results should be stored
- --clean-workdir
Clears working directory of contents. Use of this flag is notrecommended when running concurrent processes of ASLPrep.
- --resource-monitor
enable Nipype’s resource monitoring to keep track of memory and CPU usage
- --reports-only
only generate reports, don’t run workflows. This will only rerun report aggregation, not reportlet generation for specific nodes.
- --run-uuid
Specify UUID of previous run, to include error logs in report. No effect without –reports-only.
- --write-graph
Write workflow graph.
- --stop-on-first-crash
Force stopping on first crash, even if a work directory was specified.
- --notrack
Opt-out of sending tracking information of this run to the ASLPREP developers. This information helps to improve ASLPREP and provides an indicator of real world usage crucial for obtaining funding.
- --sloppy
Use low-quality tools for speed - TESTING ONLY
- --pcasl
PCASL or PASL, if not the CBF computation will assume PASL it is also secified in ASL metadata
The FreeSurfer license¶
ASLPRep uses FreeSurfer tools, which require a license to run.
To obtain a FreeSurfer license, simply register for free at https://surfer.nmr.mgh.harvard.edu/registration.html.
When using manually-prepared environments or singularity, FreeSurfer will search
for a license key file first using the $FS_LICENSE
environment variable and then
in the default path to the license key file ($FREESURFER_HOME/license.txt
).
If using the --cleanenv
flag and $FS_LICENSE
is set, use --fs-license-file $FS_LICENSE
to pass the license file location to ASLPRep.
It is possible to run the docker container pointing the image to a local path
where a valid license file is stored.
For example, if the license is stored in the $HOME/.licenses/freesurfer/license.txt
file on the host system:
$ docker run -ti --rm \
-v $HOME/fullds005:/data:ro \
-v $HOME/dockerout:/out \
-v $HOME/.licenses/freesurfer/license.txt:/opt/freesurfer/license.txt \
pennlinc/aslprep:latest \
/data /out/out \
participant \
--ignore fieldmaps
Troubleshooting¶
Logs and crashfiles are outputted into the
<output dir>/aslprep/sub-<participant_label>/log
directory.
Information on how to customize and understand these files can be found on the
nipype debugging
page.
Support and communication. The documentation of this project is found here: http://aslprep.readthedocs.org/en/latest/.
All bugs, concerns and enhancement requests for this software can be submitted here: https://github.com/pennlinc/aslprep/issues.
To participate in the ASLPRep development-related discussions please use the following mailing list: http://mail.python.org/mailman/listinfo/neuroimaging Please add [aslprep] to the subject line when posting on the mailing list.