Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to change class of a file object ("Become" page functionality) ?

0 views
Skip to first unread message

Lars Erdmann

unread,
Jun 22, 2008, 6:01:23 PM6/22/08
to
Hi,

all file objects (WPDataFile or derived) have a "Become" page (or
"Object class" ?) where you can change their class to a selection of
other compatible classes where "compatible classes" do not necessarily
have to be anchestors of the current class (they can also be children of
anchestors, therefore can be siblings of parent or grandparent etc.
classes) but I guess they are restricted to be at least of WPFileSystem
or derived classses.
The user interface is there but I cannot see what SOM method supports
that. Anyone have any insight what SOM method supports this class change
or any idea how I can debug what SOM method is called on that user action ?
I have found method somCastObjCls (defined for SOMClass class) which
maybe does the right thing. However it is not documented and therefore
the parameters not defined (also not in the interface repository) so it
will be trial and error to find the right parameters ...

Maybe the interface is: BOOL somCastObjCls(SOMClass *receiver,SOMObject
*targetObj,somId *targetClass);

Any help or hints ?

Lars

Paul Ratcliffe

unread,
Jun 22, 2008, 7:23:14 PM6/22/08
to
On Mon, 23 Jun 2008 00:01:23 +0200, Lars Erdmann <lars.e...@arcor.de> wrote:

> all file objects (WPDataFile or derived) have a "Become" page (or
> "Object class" ?) where you can change their class to a selection of
> other compatible classes where "compatible classes" do not necessarily
> have to be anchestors of the current class (they can also be children of
> anchestors, therefore can be siblings of parent or grandparent etc.
> classes) but I guess they are restricted to be at least of WPFileSystem
> or derived classses.
> The user interface is there but I cannot see what SOM method supports
> that. Anyone have any insight what SOM method supports this class change
> or any idea how I can debug what SOM method is called on that user action ?
> I have found method somCastObjCls (defined for SOMClass class) which
> maybe does the right thing.

Nobody knows, at least outside of IBM, and they aren't saying anything.
I suspect there is no method. If there was it would be a wpSomething()
method.

Rich Walsh

unread,
Jun 22, 2008, 11:57:51 PM6/22/08
to

This functionality is provided by ClassAssociationManager which is
derived directly from SOMObject. It has 3 methods:

Method Entry point
camQueryBecomeableClasses PMWP 03:0001c1dc
camBecomeInstanceOf PMWP 03:0001c104
camQueryPreviousClass PMWP 03:0001c078

BTW...
> If there was it would be [...]

This should be "If there _were_ it would be [...]"


--
== == almost usable email address: Rich AT E-vertise.Com == ==
___________________________________________________________________
|
| DragText v3.9 with NLS support
Rich Walsh | A Distinctly Different Desktop Enhancement
Ft Myers, FL | http://e-vertise.com/dragtext/
___________________________________________________________________

Lars Erdmann

unread,
Jun 23, 2008, 3:07:14 AM6/23/08
to
Great, thanks ! I think I will be able to go from there. It'll cost me a
few traps until I will have correctly figured out the parameters to pass ...

By the way: how did you know ? By guessing from the name ?

Lars

Rich Walsh schrieb:

Paul Ratcliffe

unread,
Jun 23, 2008, 8:42:39 AM6/23/08
to
On 23 Jun 2008 03:57:51 GMT, Rich Walsh <spamyo...@127.0.0.1> wrote:

> This functionality is provided by ClassAssociationManager which is
> derived directly from SOMObject. It has 3 methods:
>
> Method Entry point
> camQueryBecomeableClasses PMWP 03:0001c1dc
> camBecomeInstanceOf PMWP 03:0001c104
> camQueryPreviousClass PMWP 03:0001c078

Much obliged. Is this documented anywhere? How do you work out the parameters
and the return value? What entrypoint are they in PMWP.DLL?

(I expect you can find the latter by using DosQueryProcAddr() on all the
entrypoints in the DLL and finding one that matches the address. More
sensibly you probably resolve by method name...)

>> If there was it would be [...]
>
> This should be "If there _were_ it would be [...]"

Yes, I'm well aware of the subjunctive. Like with a lot of modern grammar, the
rules seem to be irrelevant these days. If I see one more person use "it's"
instead of "its" for the possessive.....

Rich Walsh

unread,
Jun 23, 2008, 1:15:59 PM6/23/08
to
On Mon, 23 Jun 2008 12:42:39 UTC, Paul Ratcliffe <ab...@orac12.clara34.co56.uk78> wrote:
> On 23 Jun 2008 03:57:51 GMT, Rich Walsh <spamyo...@127.0.0.1> wrote:
>
> > This functionality is provided by ClassAssociationManager which is
> > derived directly from SOMObject. It has 3 methods:
> >
> > Method Entry point
> > camQueryBecomeableClasses PMWP 03:0001c1dc
> > camBecomeInstanceOf PMWP 03:0001c104
> > camQueryPreviousClass PMWP 03:0001c078
>
> Much obliged. Is this documented anywhere? How do you work out the parameters
> and the return value? What entrypoint are they in PMWP.DLL?
>
> (I expect you can find the latter by using DosQueryProcAddr() on all the
> entrypoints in the DLL and finding one that matches the address. More
> sensibly you probably resolve by method name...)

This comes from RWX which displays the info like this:

ClassAssociationManager - 3 New methods:

032 camQueryBecomeableClasses 1f9dc1dc
033 camBecomeInstanceOf 1f9dc104
034 camQueryPreviousClass 1f9dc078

I forget whether RWX resolves methods by name or by looking at the
static methods table. I made the addresses more generic by looking
at Theseus and guessing which code segment they were in.

BTW, Lars...if you have my RWS package, you can use RwsTest to
invoke these with up to 5 arguments per call. RWS's WPS component
installs an exception handler before each call, so (hopefully) the
WPS won't crash if you get them wrong.

Lars Erdmann

unread,
Jun 23, 2008, 2:38:59 PM6/23/08
to

"Paul Ratcliffe" <ab...@orac12.clara34.co56.uk78> schrieb im Newsbeitrag
news:slrng5v6hu...@news.pr.network...

> On 23 Jun 2008 03:57:51 GMT, Rich Walsh <spamyo...@127.0.0.1> wrote:
>
>> This functionality is provided by ClassAssociationManager which is
>> derived directly from SOMObject. It has 3 methods:
>>
>> Method Entry point
>> camQueryBecomeableClasses PMWP 03:0001c1dc
>> camBecomeInstanceOf PMWP 03:0001c104
>> camQueryPreviousClass PMWP 03:0001c078
>
> Much obliged. Is this documented anywhere? How do you work out the
> parameters
> and the return value? What entrypoint are they in PMWP.DLL?

you work out the parameters by trial and error but I have a fairly good idea
what they would be.

I would be much more interested to find out what ordinals go with (as
PMWP.DLL does not export anything by name) :
ClassAssociationManagerNewClass
ClassAssociationManagerClassData
ClassAssociationManagerCClassData

They are not listed in somtk.lib but are necessary if you want to statically
access all those methods through the SOM bindings. I have started to write a
DSOM application (so that crashes won't hurt) but I cannot use namelookup
(somLookupMethod, somFindMethod) as DSOM does not support parameter type
"somID" for proxy/remote invocation (how dull) but I am getting the feeling
it might in general be easier with Rich's RWS ...

By the way: how did you find out what routine is what ordinal in your:
http://home.clara.net/orac/os2/pmwp.htm ?

Lars


Paul Ratcliffe

unread,
Jun 24, 2008, 5:24:55 PM6/24/08
to
On Mon, 23 Jun 2008 20:38:59 +0200, Lars Erdmann <lars.e...@arcor.de> wrote:

> I would be much more interested to find out what ordinals go with (as
> PMWP.DLL does not export anything by name) :
> ClassAssociationManagerNewClass
> ClassAssociationManagerClassData
> ClassAssociationManagerCClassData

There are no ordinals as those functions are not exported. The only way
you can resolve them is by SOM name lookup.

> By the way: how did you find out what routine is what ordinal in your:
> http://home.clara.net/orac/os2/pmwp.htm ?

The information was collated from lots of sources. I really can't remember
now where the PMWP info. came from, but the above is not in there and there
are no new entrypoints in the DLL.

Lars Erdmann

unread,
Jun 24, 2008, 7:56:20 PM6/24/08
to
Paul Ratcliffe schrieb:

> On Mon, 23 Jun 2008 20:38:59 +0200, Lars Erdmann <lars.e...@arcor.de> wrote:
>
>> I would be much more interested to find out what ordinals go with (as
>> PMWP.DLL does not export anything by name) :
>> ClassAssociationManagerNewClass
>> ClassAssociationManagerClassData
>> ClassAssociationManagerCClassData
>
> There are no ordinals as those functions are not exported. The only way
> you can resolve them is by SOM name lookup.

These are not SOM methods. These are the data structures that allow SOM
to find the methods and the function that builds the class
(ClassAssociationManagerNewClass). So I will not be able to find them
with SOM means ...

>
>> By the way: how did you find out what routine is what ordinal in your:
>> http://home.clara.net/orac/os2/pmwp.htm ?
>
> The information was collated from lots of sources.

So you did not write yourself a utility to somehow parse the DLLs and
find out (also for all the other DLLs) ? Is there a way this could be done ?

Lars

Rich Walsh

unread,
Jun 24, 2008, 11:37:30 PM6/24/08
to
On Tue, 24 Jun 2008 23:56:20 UTC, Lars Erdmann <lars.e...@arcor.de> wrote:
> Paul Ratcliffe schrieb:
> > On Mon, 23 Jun 2008 20:38:59 +0200, Lars Erdmann <lars.e...@arcor.de> wrote:
> >
> >> I would be much more interested to find out what ordinals go with (as
> >> PMWP.DLL does not export anything by name) :
> >> ClassAssociationManagerNewClass
> >> ClassAssociationManagerClassData
> >> ClassAssociationManagerCClassData
> >
> > There are no ordinals as those functions are not exported. The only way
> > you can resolve them is by SOM name lookup.
>
> These are not SOM methods. These are the data structures that allow SOM
> to find the methods and the function that builds the class
> (ClassAssociationManagerNewClass). So I will not be able to find them
> with SOM means ...

Why would you need them? ClassAssociationManager is always loaded and
available within the WPS process. Of what value is it outside the WPS?

> >> By the way: how did you find out what routine is what ordinal in your:
> >> http://home.clara.net/orac/os2/pmwp.htm ?
> >
> > The information was collated from lots of sources.
>
> So you did not write yourself a utility to somehow parse the DLLs and
> find out (also for all the other DLLs) ? Is there a way this could be done ?

Couldn't some of this be gotten from various .sym and trace files?

BTW... I was able to use RwsTest to call camBecomeInstanceOf and
camQueryPreviousClass:

pNewObj = camBecomeInstanceOf( pCamObj, pOldObj, pNewClass);

fOK = camQueryPreviousClass( pCamObj, pObj, pszClassName);

I couldn't figure out what all of the arguments for
camQueryBecomeableClasses might be. It's something like this:

cntClasses = camQueryBecomeableClasses( pCamObj, pObj, (pBuf?) );
or
cntClasses = camQueryBecomeableClasses( pCamObj, pObj, (cbBuf?), (pBuf?) );

Lars Erdmann

unread,
Jun 25, 2008, 12:15:28 PM6/25/08
to
Hallo,

"Rich Walsh" <spamyo...@127.0.0.1> schrieb im Newsbeitrag
news:brddYgxvE0gm-pn2-RtPdZcBQrYek@localhost...


> On Tue, 24 Jun 2008 23:56:20 UTC, Lars Erdmann <lars.e...@arcor.de>
> wrote:
>> Paul Ratcliffe schrieb:
>> > On Mon, 23 Jun 2008 20:38:59 +0200, Lars Erdmann
>> > <lars.e...@arcor.de> wrote:
>> >
>> >> I would be much more interested to find out what ordinals go with (as
>> >> PMWP.DLL does not export anything by name) :
>> >> ClassAssociationManagerNewClass
>> >> ClassAssociationManagerClassData
>> >> ClassAssociationManagerCClassData
>> >
>> > There are no ordinals as those functions are not exported. The only way
>> > you can resolve them is by SOM name lookup.
>>
>> These are not SOM methods. These are the data structures that allow SOM
>> to find the methods and the function that builds the class
>> (ClassAssociationManagerNewClass). So I will not be able to find them
>> with SOM means ...
>
> Why would you need them? ClassAssociationManager is always loaded and
> available within the WPS process. Of what value is it outside the WPS?

DSOM requires you to create the class (and all parent classes) in your local
process even if you want to access a remote class object through
"somdGetClassObj", that is:

ClassAssociationManagerNewClass(ClassAssociationManager_MajorVersion,ClassAssociationManager_MinorVersion)

has to be called within your process. I am able to create the C/C++ bindings
(I just hacked an IDL file) but the 3 above variables/routines are expected
to exist in the class DLL (PMWP.DLL in this case). But somtk.lib does not
export these symbols ...

I can get to the class via DSOM but I cannot get an object. I cannot create
another Cam object either, neither locally ("somNew") nor remote
("somdCreateObject").
But the "cam..." methods only work if I have a Cam object (the class object
doesn't help).

>
>> >> By the way: how did you find out what routine is what ordinal in your:
>> >> http://home.clara.net/orac/os2/pmwp.htm ?
>> >
>> > The information was collated from lots of sources.
>>
>> So you did not write yourself a utility to somehow parse the DLLs and
>> find out (also for all the other DLLs) ? Is there a way this could be
>> done ?
>
> Couldn't some of this be gotten from various .sym and trace files?
>
> BTW... I was able to use RwsTest to call camBecomeInstanceOf and
> camQueryPreviousClass:
>
> pNewObj = camBecomeInstanceOf( pCamObj, pOldObj, pNewClass);
>
> fOK = camQueryPreviousClass( pCamObj, pObj, pszClassName);
>
> I couldn't figure out what all of the arguments for
> camQueryBecomeableClasses might be. It's something like this:
>
> cntClasses = camQueryBecomeableClasses( pCamObj, pObj, (pBuf?) );
> or
> cntClasses = camQueryBecomeableClasses( pCamObj, pObj, (cbBuf?),
> (pBuf?) );

Thanks very much for that ! Eventually I will move over to RWS. But how did
YOU get to a Cam object ? Or were you able to create one from the Class
object (within the WPS process) ?

Lars


Rich Walsh

unread,
Jun 26, 2008, 7:57:15 AM6/26/08
to
On Wed, 25 Jun 2008 16:15:28 UTC, "Lars Erdmann" <lars.e...@arcor.de> wrote:

> > BTW... I was able to use RwsTest to call camBecomeInstanceOf and
> > camQueryPreviousClass:
>

> Thanks very much for that ! Eventually I will move over to RWS. But how did
> YOU get to a Cam object ? Or were you able to create one from the Class
> object (within the WPS process) ?

I called somNew on the CAM class object. I had RwsTest return the
object's pointer, then used that as-is for subsequent calls.

Lars Erdmann

unread,
Jun 27, 2008, 4:16:41 PM6/27/08
to
Rich Walsh schrieb:

> On Wed, 25 Jun 2008 16:15:28 UTC, "Lars Erdmann" <lars.e...@arcor.de> wrote:
>
>>> BTW... I was able to use RwsTest to call camBecomeInstanceOf and
>>> camQueryPreviousClass:
>> Thanks very much for that ! Eventually I will move over to RWS. But how did
>> YOU get to a Cam object ? Or were you able to create one from the Class
>> object (within the WPS process) ?
>
> I called somNew on the CAM class object. I had RwsTest return the
> object's pointer, then used that as-is for subsequent calls.
>
>
Sorry to ask again but how did you then get the pointer to the CAM class
object ?

Lars

Rich Walsh

unread,
Jun 28, 2008, 12:28:45 AM6/28/08
to

Using RwsTest, all I had to do was supply the name of the class
and identify it as such (i.e. RWSI_CNAME). In effect:
pObj = somNew( "ClassAssociationManager");

In the WPS process, RWS turned the name into something usable.
First it converted the name to a somId, then called somClassFromId
on the SOMClassMgr object (SOMClassMgrObject is a global variable
exported by som.dll). Once it had the class object, it invoked the
requested method and returned the result:
pObj = somNew( pClass);

Nobody

unread,
Jun 28, 2008, 8:30:02 AM6/28/08
to
Rich Walsh wrote:
> On Fri, 27 Jun 2008 20:16:41 UTC, Lars Erdmann <lars.e...@arcor.de> wrote:
>> Rich Walsh schrieb:
>>> On Wed, 25 Jun 2008 16:15:28 UTC, "Lars Erdmann" <lars.e...@arcor.de> wrote:
>>>
>> Sorry to ask again but how did you then get the pointer to the CAM class
>> object ?
>
> Using RwsTest, all I had to do was supply the name of the class
> and identify it as such (i.e. RWSI_CNAME). In effect:
> pObj = somNew( "ClassAssociationManager");
>
> In the WPS process, RWS turned the name into something usable.
> First it converted the name to a somId, then called somClassFromId
> on the SOMClassMgr object (SOMClassMgrObject is a global variable
> exported by som.dll). Once it had the class object, it invoked the
> requested method and returned the result:
> pObj = somNew( pClass);
>
>

My God, I'm impressed. You've dug into the heart of OS/2 and its WPS,
and discovered what nobody else new about.

Thank you!

Lars Erdmann

unread,
Jun 28, 2008, 10:06:04 AM6/28/08
to
Hallo,

>> Sorry to ask again but how did you then get the pointer to the CAM class
>> object ?
>
> Using RwsTest, all I had to do was supply the name of the class
> and identify it as such (i.e. RWSI_CNAME). In effect:
> pObj = somNew( "ClassAssociationManager");
>
> In the WPS process, RWS turned the name into something usable.
> First it converted the name to a somId, then called somClassFromId
> on the SOMClassMgr object (SOMClassMgrObject is a global variable
> exported by som.dll). Once it had the class object, it invoked the
> requested method and returned the result:
> pObj = somNew( pClass);

...which tells me that I have not yet fully understood RWS API. I thought
even with RWS you always would have to pass an object pointer to ANY wps
method you are calling as the very first parameter. Obviously not. I'll dig
into that.

Thanks a lot.

Lars


Lars Erdmann

unread,
Jun 28, 2008, 11:07:47 AM6/28/08
to
Rich Walsh schrieb:

> On Fri, 27 Jun 2008 20:16:41 UTC, Lars Erdmann <lars.e...@arcor.de> wrote:
>> Rich Walsh schrieb:
>>> On Wed, 25 Jun 2008 16:15:28 UTC, "Lars Erdmann" <lars.e...@arcor.de> wrote:
>>>
>>>>> BTW... I was able to use RwsTest to call camBecomeInstanceOf and
>>>>> camQueryPreviousClass:
>>>> Thanks very much for that ! Eventually I will move over to RWS. But how did
>>>> YOU get to a Cam object ? Or were you able to create one from the Class
>>>> object (within the WPS process) ?
>>> I called somNew on the CAM class object. I had RwsTest return the
>>> object's pointer, then used that as-is for subsequent calls.
>>>
>> Sorry to ask again but how did you then get the pointer to the CAM class
>> object ?
>
> Using RwsTest, all I had to do was supply the name of the class
> and identify it as such (i.e. RWSI_CNAME). In effect:
> pObj = somNew( "ClassAssociationManager");
>
> In the WPS process, RWS turned the name into something usable.
> First it converted the name to a somId, then called somClassFromId
> on the SOMClassMgr object (SOMClassMgrObject is a global variable
> exported by som.dll). Once it had the class object, it invoked the
> requested method and returned the result:
> pObj = somNew( pClass);
>
>

Ehmm, could you give me the RWSTEST usage equivalence of:

get ClassAssociationManager class object clsCAM
get WPFileSystem class object clsFSys

ClassAssociationManager *pCAM = clsCAM->somNew();
WPDataFile *fOld = (WPDataFile
*)clsFSys->wpclsQueryObjectFromPath("d:\bla\bla test.txt")
fNew = pCAM->camBecomeInstanceOf(fOld,"IWFProject")
fOld->wpUnlockObject();
fNew->wpUnlockObject(); // Is that necessary ? I would guess so ...
pCAM->somFree();

So sorry but I have some problems finding my way through the RWS API.
But I am learning well from examples ...

Thanks, Lars

Rich Walsh

unread,
Jun 28, 2008, 2:51:43 PM6/28/08
to

Pointers to objects are either not accessible or not useful outside the
WPS, so RWS converts what you have available on input into an object
(e.g., a path or a handle or some info from a DRAGITEM structure).
If requested, it also converts objects into something usable on output
(e.g. a path, handle, icon, etc.). Of course, RWS doesn't know what
to do unless you tell it. Consequently, each argument to a method
requires 3 arguments to RWS: type, size, and value.

Type identifies the conversion. RWSI_OPATH means "convert this f/q
path into a file object"; RWSI_CNAME means "convert this class name
into a class object"; RWSI_ASIS means "pass this value as-is"; etc.

Size is usually zero because RWS can figure out the size of pointers,
strings, etc., itself. It's only needed when you want to pass a
buffer of some arbitrary size. (BTW... in RwsTest, Size is decimal.)

Value is whatever you're passing in: a string, some hex value, etc.
If you're passing a buffer that the method will fill (RWSI_PBUF),
value can be null (or blank in RwsTest) - RWS will init it to zeros.

This system extends to copying data across process boundaries. If
some method returns a pointer to a buffer allocated from SOM memory,
there's a Type to copy the data into shared memory then free the
SOM buffer. *Any* get or put operation should be possible when RWS
is called by a C program. RwsTest can be handy for experimenting
but it isn't quite so flexible (and unlike RWS itself, it has a
few bugs).

Overall, RWS _is_ a little clumsy to use at first, but it's really
not too hard once you get the hang of it.

Rich Walsh

unread,
Jun 28, 2008, 3:10:34 PM6/28/08
to
On Sat, 28 Jun 2008 15:07:47 UTC, Lars Erdmann <lars.e...@arcor.de> wrote:

> Ehmm, could you give me the RWSTEST usage equivalence of:
>
> get ClassAssociationManager class object clsCAM
> get WPFileSystem class object clsFSys
>
> ClassAssociationManager *pCAM = clsCAM->somNew();
> WPDataFile *fOld = (WPDataFile
> *)clsFSys->wpclsQueryObjectFromPath("d:\bla\bla test.txt")
> fNew = pCAM->camBecomeInstanceOf(fOld,"IWFProject")
> fOld->wpUnlockObject();
> fNew->wpUnlockObject(); // Is that necessary ? I would guess so ...
> pCAM->somFree();
>
> So sorry but I have some problems finding my way through the RWS API.
> But I am learning well from examples ...

Many of the calls shown above aren't needed because RWS performs them
automatically as it converts, e.g., a path into an object pointer.
(See my previous post for info about Type, Size, and Value.)


TYPE SIZE VALUE
---- ---- -----
-> Proc: RWSP_MNAM somNew
Arg1: RWSI_CNAME 0 ClassAssociationManager
Return: RWSR_ASIS 0

In the Result window, you'll see the values used by the method call.
Arg0 is the return - in this case, a pointer to a C-A-M object.
You'll copy/paste this into Arg1 in the subsequent calls.


-> Proc: RWSP_MNAM camBecomeInstanceOf
Arg1: RWSI_ASIS 0 13bafd8 [ptr to my CAM object]
Arg2: RWSI_OPATH 0 d:\bla\bla test.txt
Arg3: RWSI_CNAME 0 IWFProject
Return: RWSR_ASIS 0

Arg0 in the Results window is a pointer to the newly created
object of class IWFProject (AFAIK, the old object is destroyed
automatically).


-> Proc: RWSP_MNAM somFree
Arg1: RWSI_ASIS 0 13bafd8
Return: RWSR_VOID 0

RwsTest will display "Error getting result!" for Arg0 but you can
ignore it - apparently it doesn't handle void returns correctly
(RWS itself doesn't have this problem).


-> Proc: RWSP_MNAM wpUnlockObject
Arg1: RWSI_ASIS 0 45064c4 [ptr to my file object]
Return: RWSR_ASIS 0

I have no idea if this is needed or even works. It often seems
as though objects don't go dormant anymore. (Note: RWS does
*not* unlock objects on its own because it has no way of knowing
whether you'll be using them again.)

If you'd like to see this rendered in C, let me know.

Lars Erdmann

unread,
Jun 29, 2008, 6:50:53 AM6/29/08
to
Hallo,

I tried to figure out camQueryBecomeableClasses parameters. The RWS
equivalent of:

rc = camQueryBecomeableClasses(ClassAssociationManager *pCAM,SOMObject
*theObj,PVOID pBuf) (rc = BOOL ? or "number of Classes" ?, I don't know).

returns sucessfully but looking at the buffer pBuf (with Theseus) shows me
it was not filled with anything (all Zeros).


As far as I understand RWS can take a buffer
where the first DWORD in the buffer specifies its length
(RWSI_PBUFLENGTHFROMULONG or something like that)
and I would like to try that one out.
Question is, how do I get this length information into the buffer ? Or does
RWS copy the "value" field into the buffer as the first DWORD ?
Question2: Is there any other way to look into the buffer apart form using
Theseus ?
I didn't quite catch the conversion (where you do not specify ...MNAME as
the operation but rather "Conversion").

Lars

Rich Walsh

unread,
Jun 29, 2008, 12:26:33 PM6/29/08
to
On Sun, 29 Jun 2008 10:50:53 UTC, "Lars Erdmann" <lars.e...@arcor.de> wrote:

> I tried to figure out camQueryBecomeableClasses parameters.

OK, I finally got it:

rc = camQueryBecomeableClasses( ClassAssociationManager * pCAM,
SOMObject * theObj,
SOMClass ** aClasses,
ULONG cntClassPtrs);

cntClassPtrs specifies the size of the 'aClasses' array. When it's
zero, rc identifies the total number of class pointers that could
be returned. When it's non-zero, rc is always zero (at least if
the call is successful).

Your call succeeded in returning the class count even though you
didn't specify cntClassPtrs because of a peculiarity/optimization
in RWS that causes it to push zeros onto the stack in some cases.

Here's an example using the venerable "macaw.avi":

-Type- -Size- -Value-
-> Proc: RWSP_MNAMI camQueryBecomeableClasses
Arg1: RWSI_ASIS 0 135dad4 [ptr to my CAM object]
Arg2: RWSI_OPATH 0 F:\MMOS2\MOVIES\MACAW.AVI
Arg3: RWSI_PBUF 32 [supply an empty 32-byte buffer]
Arg4: RWSI_ASIS 0 8 [return a max of 8 class ptrs]
Return: RWSR_ASIS 0

Result:
pHdr= 18530040
arg0 - value= 0
arg1 - value= 135dad4
arg2 - value= 4790fe8
arg3 - size= 32 value*= 18530104
00ae6f78 00cdd1e4 00d05950 00000000
00000000 00000000 00000000 00000000
arg4 - value= 8


> Is there any other way to look into the buffer apart form using
> Theseus ?

As you can see, if your buffer is <= 128 bytes, RwsTest will display it.
Otherwise, it's Theseus (note that arg3 shows the address of the buffer).

BTW... the 3 class pointers are: WPDataFile, MMAVI, and MMVideo. I used
my "RWX - Class Explorer" to identify them, but you could also use RwsTest
like this:

-Type- -Size- -Value-
-> Proc: RWSP_CONV
Arg1: RWSC_CLASS_CNAME 0 00ae6f78
Arg2: RWSC_CLASS_CNAME 0 00cdd1e4
Arg3: RWSC_CLASS_CNAME 0 00d05950
Return: RWSR_ASIS 0

Result:
pHdr= 18530040
arg0 - value= 3
arg1 - string= WPDataFile
arg2 - string= MMAVI
arg3 - string= MMVideo

Lars Erdmann

unread,
Jun 29, 2008, 5:31:43 PM6/29/08
to
Thank you very much for the info !

Lars

"Rich Walsh" <spamyo...@127.0.0.1> schrieb im Newsbeitrag

news:brddYgxvE0gm-pn2-MUdShdknEMih@localhost...

Lars Erdmann

unread,
Jul 2, 2008, 12:56:44 PM7/2/08
to
Hi Rich,

>
> RwsTest will display "Error getting result!" for Arg0 but you can
> ignore it - apparently it doesn't handle void returns correctly
> (RWS itself doesn't have this problem).
>
>
> -> Proc: RWSP_MNAM wpUnlockObject
> Arg1: RWSI_ASIS 0 45064c4 [ptr to my file object]
> Return: RWSR_ASIS 0
>
> I have no idea if this is needed or even works. It often seems
> as though objects don't go dormant anymore. (Note: RWS does
> *not* unlock objects on its own because it has no way of knowing
> whether you'll be using them again.)
>
> If you'd like to see this rendered in C, let me know.

Sorry to bother again. I want the equivalent of :

PSZ fileType;
PFILEFINDBUF3 pF;
...
fileType =
_wpQueryType(_WPFileSystem->wpclsQueryObjectFromPath(pF->achName));

I thought this would be:

rc = RwsCall(&rwsHdr,
RWSP_MNAM,(ULONG)"wpQueryType",
RWSR_PSTR,0UL,1UL,
RWSI_OPATH,pF->cchName,pF->achName);

fileType = (PSZ)RwsGetResult(rwsHdr,0UL,0UL);


but for "rc" I get error RWSSRV_ARGGIVECONVFAILED. Could you tell me
what I am doing wrong ? By the way: pF (as much as pF->achName) points
to BSS memory (in other words: not on the stack).

Lars

Rich Walsh

unread,
Jul 2, 2008, 11:06:50 PM7/2/08
to
On Wed, 2 Jul 2008 16:56:44 UTC, Lars Erdmann <lars.e...@arcor.de> wrote:

> I want the equivalent of :
>
> PSZ fileType;
> PFILEFINDBUF3 pF;
> ...
> fileType =
> _wpQueryType(_WPFileSystem->wpclsQueryObjectFromPath(pF->achName));
>
> I thought this would be:
>
> rc = RwsCall(&rwsHdr,
> RWSP_MNAM,(ULONG)"wpQueryType",
> RWSR_PSTR,0UL,1UL,
> RWSI_OPATH,pF->cchName,pF->achName);
>
> fileType = (PSZ)RwsGetResult(rwsHdr,0UL,0UL);
>
>
> but for "rc" I get error RWSSRV_ARGGIVECONVFAILED. Could you tell
> me what I am doing wrong ?

The most likely reason is that the filename is unqualified, so it
can't be found. Add a path and it should work.

> By the way: pF (as much as pF->achName) points to BSS memory
> (in other words: not on the stack).

It doesn't matter where the string is because RwsClient has to copy
it into shared memory so the WPS process can access it. Also, you
don't need to specify the string's length since RwsClient will do
a strlen() and ignore what you specified. This is an unfortunate
design flaw given what follows...

Below is some sample code that shows how to greatly increase RWS's
efficiency & virtually eliminate its overhead when you call it in
a loop (in this example, to change the class of multiple files).

The key is to reuse the data structure that RWS creates on the
first call. When it returns, all of the info that RWS had to
look up is now stored in the struct. To reuse the method PFN
and class pointer, you just change those items' 'type' fields to
have RWS use their existing values. Since the name of the file
object in the sample changes from call to call, you won't change
that one's type. Instead, you'll just copy the name into the
appropriate buffer yourself before each call.

Here's the "unfortunate" part: the filename buffer really should
be CCHMAXPATH, but when you specify a string argument, RwsClient
only allocates enough space for that string. To work around this
flaw, the code asks for an empty buffer then changes the argument's
type to what it should be & copies in the first filename.


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

ULONG ReClass( char * pszClass, char ** apszFiles, ULONG cntFiles)
{
ULONG rc;
ULONG ctr = 0;
ULONG camObj = 0;
PRWSHDR pHdr = 0;
PRWSDSC pArg;
char * pBuf;

do {
// create a ClassAssociationManager object
rc = RwsCall( &pHdr,
RWSP_MNAM, (ULONG)"somNew", // call type
RWSR_ASIS, 0, // return type
1, // nbr of args
RWSI_CNAME, 0, "ClassAssociationManager"); // class name
if (rc)
break;

// get a pointer to the struct containing the return;
// save its value, then free the RWS request structure
pArg = CALCRTNPTR( pHdr);
camObj = pArg->value;
RwsFreeMem( pHdr);
pHdr = 0;

// build a new request structure but don't dispatch it
rc = RwsBuild( &pHdr,
RWSP_MNAM, (ULONG)"camBecomeInstanceOf", // call type
RWSR_ASIS, 0, // return type
3, // nbr of args
RWSI_ASIS, 0, camObj, // C-A-Mgr object
RWSI_PBUF, 260, 0, // filename buffer
RWSI_CNAME, 0, (ULONG)"IWFProject"); // new class name
if (rc)
break;

// get a pointer to Arg2 (the filename buffer)
rc = RwsGetArgPtr( pHdr, 2, &pArg);
if (rc)
break;

// change its type to "convert file path to object"; get a ptr to
// the buffer where it stores the path, then copy in the first file
pArg->type = RWSI_OPATH;
pBuf = CALCGIVEPTR( pArg);
strcpy( pBuf, apszFiles[ctr++]);

// dispatch the request to RwsServer; if there's only 1 file, exit
rc = RwsDispatch( pHdr);
if (rc || ctr >= cntFiles)
break;

// the struct containing the method name now has a ptr to the
// function that implements it, so change the type to "method PFN"
pArg = CALCPROCPTR( pHdr);
pArg->type = RWSP_MPFN;

// the struct containing the class name now has a ptr to the
// class object, so change the type to "use value as-is"
rc = RwsGetArgPtr( pHdr, 3, &pArg);
if (rc)
break;
pArg->type = RWSI_ASIS;

// for the remaining files, copy the name into place,
// then dispatch the request to RwsServer
while (ctr < cntFiles) {
strcpy( pBuf, apszFiles[ctr++]);
rc = RwsDispatch( pHdr);
if (rc)
break;
}

} while (0);

// if we created a C-A-Mgr object, delete it
if (camObj) {
if (pHdr)
RwsFreeMem( pHdr);
pHdr = 0;

RwsCall( &pHdr,
RWSP_MNAMI, (ULONG)"somFree", // call type
RWSR_VOID, 0, // return type
1, // nbr of args
RWSI_ASIS, 0, camObj); // C-A-Mgr object
}

// free the RWS request structure
if (pHdr)
RwsFreeMem( pHdr);

return (rc);
}

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

Lars Erdmann

unread,
Jul 7, 2008, 3:10:21 PM7/7/08
to
Hi,


Rich Walsh schrieb:


> On Wed, 2 Jul 2008 16:56:44 UTC, Lars Erdmann <lars.e...@arcor.de> wrote:
>
>> I want the equivalent of :
>>
>> PSZ fileType;
>> PFILEFINDBUF3 pF;
>> ...
>> fileType =
>> _wpQueryType(_WPFileSystem->wpclsQueryObjectFromPath(pF->achName));
>>
>> I thought this would be:
>>
>> rc = RwsCall(&rwsHdr,
>> RWSP_MNAM,(ULONG)"wpQueryType",
>> RWSR_PSTR,0UL,1UL,
>> RWSI_OPATH,pF->cchName,pF->achName);
>>
>> fileType = (PSZ)RwsGetResult(rwsHdr,0UL,0UL);
>>
>>
>> but for "rc" I get error RWSSRV_ARGGIVECONVFAILED. Could you tell
>> me what I am doing wrong ?
>
> The most likely reason is that the filename is unqualified, so it
> can't be found. Add a path and it should work.

Ah right. Yes that was the problem.

>
>> By the way: pF (as much as pF->achName) points to BSS memory
>> (in other words: not on the stack).
>
> It doesn't matter where the string is because RwsClient has to copy
> it into shared memory so the WPS process can access it. Also, you
> don't need to specify the string's length since RwsClient will do
> a strlen() and ignore what you specified. This is an unfortunate
> design flaw given what follows...
>
> Below is some sample code that shows how to greatly increase RWS's
> efficiency & virtually eliminate its overhead when you call it in
> a loop (in this example, to change the class of multiple files).
>
> The key is to reuse the data structure that RWS creates on the
> first call. When it returns, all of the info that RWS had to
> look up is now stored in the struct. To reuse the method PFN
> and class pointer, you just change those items' 'type' fields to
> have RWS use their existing values. Since the name of the file
> object in the sample changes from call to call, you won't change
> that one's type. Instead, you'll just copy the name into the
> appropriate buffer yourself before each call.
>
> Here's the "unfortunate" part: the filename buffer really should
> be CCHMAXPATH, but when you specify a string argument, RwsClient
> only allocates enough space for that string. To work around this
> flaw, the code asks for an empty buffer then changes the argument's
> type to what it should be & copies in the first filename.

Do you plan to remove that design flaw :-) ?

anyway: Yes that seems to be simple for ONE wps method call. But how about:

pCAM = SOMClassMgrObject->somClassFromId(id1 =
somIdFromString("ClassAssociationManager"))->somNew();
pClass = SOMClassMgrObject->somClassFromId(id2 =
somIdFromString("IWFProject"));

for (i in allFiles)
{
pFileObj = _WPFileSystem->wpclsQueryObjectFromPath(fileSpec[i]);
ulAttrs = pFileObj->wpQueryAttr();
pFileObj->wpSetAttr(ulAttrs &
~(FILE_READONLY|FILE_HIDDEN|FILE_SYSTEM));
pFileObj->wpSetup("DEFAULTVIEW=DEFAULT");
pCAM->camBecomeInstanceOf(pFileObj,pClass);
pFileObj->wpUnlockObject();
}
pCAM->somFree();
SOMFree(id2);
SOMFree(id1);

As I understand, I will need to call RwsBuild for each method in the
"for" loop (and keeping track of that many RWS headers):
"wpQueryAttr","wpSetAttr","wpSetup","camBecomeInstanceOf","wpUnlockObject"
correct ?
(I understand that "somIdFromString","somClassFromId",
"wpclsQueryObjectFromPath" are called by RWS implicitely. How about
SOMFree to free the somId ?).

or does RWS provide a way to set up a whole sequence of methods with a
single "Build" call (and receive all the converted values when invoking
the RwsDispatch call) ?


Lars


Rich Walsh

unread,
Jul 8, 2008, 9:49:29 PM7/8/08
to
On Mon, 7 Jul 2008 19:10:21 UTC, Lars Erdmann <lars.e...@arcor.de> wrote:
> Rich Walsh schrieb:

> > when you specify a string argument, RwsClient
> > only allocates enough space for that string.
>

> Do you plan to remove that design flaw :-) ?

If there's ever an RWS v0.90 then yes, certainly.

> or does RWS provide a way to set up a whole sequence of methods with a
> single "Build" call (and receive all the converted values when invoking
> the RwsDispatch call) ?

The ability to chain methods like that would be my primary reason for
developing RWS further.

> that [the sample code] seems to be simple for ONE wps method call.


> But how about:
>
> pCAM = SOMClassMgrObject->somClassFromId(id1 =
> somIdFromString("ClassAssociationManager"))->somNew();
> pClass = SOMClassMgrObject->somClassFromId(id2 =
> somIdFromString("IWFProject"));
>
> for (i in allFiles)
> {
> pFileObj = _WPFileSystem->wpclsQueryObjectFromPath(fileSpec[i]);
> ulAttrs = pFileObj->wpQueryAttr();
> pFileObj->wpSetAttr(ulAttrs &
> ~(FILE_READONLY|FILE_HIDDEN|FILE_SYSTEM));
> pFileObj->wpSetup("DEFAULTVIEW=DEFAULT");
> pCAM->camBecomeInstanceOf(pFileObj,pClass);
> pFileObj->wpUnlockObject();
> }
> pCAM->somFree();
> SOMFree(id2);
> SOMFree(id1);

Below are two implementations of the above: one that's very minimally
optimized and one where everything is optimized. Not surprisingly,
the first is pretty straight-forward while the second is ..uhh.. messy.
OTOH, when you get to the loop that handles the 2nd & subsequent files,
it's extremely simple. The first would be suitable for occassionally
changing the class of a few files; the second would be appropriate if
you plan to change hundreds of files on a regular basis.

In both cases, a prime optimization is eliminating calls that don't
have to be done by the WPS, namely getting & setting file attributes.
Instead of wpQuery/SetAttr(), I used DosQuery/SetPathInfo().

I also made a small but important change: camBecomeInstanceOf() is
called *before* the other WPS calls. This is very important in the
maximally optimized version because it applies the first file object's
methods to every subsequent file. Before camBecome, you can't be sure
every file is of the same class and uses the same method implementation.
After camBecome, you're guaranteed that each object's wpSetup & wpUnlock
is identical.

BTW... I haven't compiled these samples, so they could have stupid
errors (i.e. they're just like IBM's samples :-)


/***************************************************************************/

// minimal optimization - should be OK for a few dozen files

ULONG ReClassMin( char * pszClass, char ** apszFiles, ULONG cntFiles)
{
ULONG rc;
ULONG ctr;
ULONG camObj = 0;
ULONG clsObj;
ULONG newObj;
FILESTATUS3 fs3;


PRWSHDR pHdr = 0;
PRWSDSC pArg;

do {
// create a ClassAssociationManager object, save the
// returned value, then free the RWS request structure


rc = RwsCall( &pHdr,
RWSP_MNAM, (ULONG)"somNew", // call type
RWSR_ASIS, 0, // return type
1, // nbr of args
RWSI_CNAME, 0, "ClassAssociationManager"); // class name
if (rc) break;

camObj = RwsGetResult( pHdr, 0, 0);


RwsFreeMem( pHdr);
pHdr = 0;

// convert the classname into a class object ptr, save
// the result, then free the RWS request structure
rc = RwsCall( &pHdr,
RWSP_CONV, 0, // call type


RWSR_ASIS, 0, // return type
1, // nbr of args

RWSC_CNAME_CLASS, 0, pszClass); // class name
if (rc) break;
clsObj = RwsGetResult( pHdr, 1, 0);


RwsFreeMem( pHdr);
pHdr = 0;

for (ctr = 0; ctr < cntFiles; ctr++) {

// reset the file's attributes
rc = DosQueryPathInfo( apszFiles[ctr], FIL_STANDARD, &fs3, sizeof(fs3));
if (rc) break;
fs3.attrFile &= ~(FILE_READONLY|FILE_HIDDEN|FILE_SYSTEM);
rc = DosSetPathInfo( apszFiles[ctr], FIL_STANDARD, &fs3, sizeof(fs3), 0);
if (rc) break;

// execute "camBecomeInstanceOf" on the file,
// then save the new object ptr created by the call
rc = RwsCall( &pHdr,


RWSP_MNAM, (ULONG)"camBecomeInstanceOf", // call type
RWSR_ASIS, 0, // return type
3, // nbr of args
RWSI_ASIS, 0, camObj, // C-A-Mgr object

RWSI_OPATH, 0, apszFiles[ctr], // filename buffer
RWSI_ASIS, 0, clsObj); // new class name
if (rc) break;
newObj = RwsGetResult( pHdr, 0, 0);


RwsFreeMem( pHdr);
pHdr = 0;

// execute "wpSetup" on the new object
rc = RwsCall( &pHdr,
RWSP_MNAM, (ULONG)"wpSetup", // call type


RWSR_ASIS, 0, // return type

2, // nbr of args
RWSI_ASIS, 0, newObj, // file object
RWSI_PSTR, 0, "DEFAULTVIEW=OPEN_RUNNING"); // setup string
if (rc) break;


RwsFreeMem( pHdr);
pHdr = 0;

// execute "wpUnlockObject" on the new object
rc = RwsCall( &pHdr,
RWSP_MNAM, (ULONG)"wpUnlockObject", // call type


RWSR_ASIS, 0, // return type
1, // nbr of args

RWSI_ASIS, 0, newObj); // file object
if (rc) break;


RwsFreeMem( pHdr);
pHdr = 0;
}

} while (0);

// if we created a C-A-Mgr object, delete it
if (camObj) {
if (pHdr)
RwsFreeMem( pHdr);
pHdr = 0;

RwsCall( &pHdr,
RWSP_MNAMI, (ULONG)"somFree", // call type
RWSR_VOID, 0, // return type
1, // nbr of args
RWSI_ASIS, 0, camObj); // C-A-Mgr object
}

// free the RWS request structure
if (pHdr)
RwsFreeMem( pHdr);

return (rc);
}

/***************************************************************************/

// maximal optimization - appropriate for hundreds or thousands of files

ULONG ReClassMax( char * pszClass, char ** apszFiles, ULONG cntFiles)
{
ULONG rc;
ULONG ctr;
ULONG camObj = 0;
FILESTATUS3 fs3;
PULONG pNewObj;
PULONG pSetupObj;
PULONG pUnlockObj;
PRWSHDR pHdr = 0;
PRWSHDR pHdrBecome = 0;
PRWSHDR pHdrSetup = 0;
PRWSHDR pHdrUnlock = 0;


PRWSDSC pArg;
char * pBuf;

do {
// create a ClassAssociationManager object
rc = RwsCall( &pHdr,
RWSP_MNAM, (ULONG)"somNew", // call type
RWSR_ASIS, 0, // return type
1, // nbr of args
RWSI_CNAME, 0, "ClassAssociationManager"); // class name
if (rc) break;

// get return value, then free the RWS request structure
camObj = CALCRTNPTR( pHdr)->value;


RwsFreeMem( pHdr);
pHdr = 0;

// reset the first file's attributes
rc = DosQueryPathInfo( apszFiles[0], FIL_STANDARD, &fs3, sizeof(fs3));
if (rc) break;
fs3.attrFile &= ~(FILE_READONLY|FILE_HIDDEN|FILE_SYSTEM);
rc = DosSetPathInfo( apszFiles[0], FIL_STANDARD, &fs3, sizeof(fs3), 0);
if (rc) break;

// build a request structure for "camBecomeInstanceOf"
// but don't dispatch it
rc = RwsBuild( &pHdrBecome,


RWSP_MNAM, (ULONG)"camBecomeInstanceOf", // call type
RWSR_ASIS, 0, // return type
3, // nbr of args
RWSI_ASIS, 0, camObj, // C-A-Mgr object
RWSI_PBUF, 260, 0, // filename buffer

RWSI_CNAME, 0, (ULONG)pszClass); // new class name
if (rc) break;

// fix arg2's type, then copy the first filename into its buffer
rc = RwsGetArgPtr( pHdrBecome, 2, &pArg);
if (rc) break;


pArg->type = RWSI_OPATH;
pBuf = CALCGIVEPTR( pArg);

strcpy( pBuf, apszFiles[0]);

// dispatch the call - it destroys the original file object
// and returns a ptr to a newly created object
rc = RwsDispatch( pHdrBecome);
if (rc) break;

// lock in the classname & method ptrs, then
// save a ptr to the return value (the new object)
pArg->pnext->type = RWSI_ASIS;
CALCPROCPTR( pHdrBecome)->type = RWSP_MPFN;
pNewObj = &(CALCRTNPTR( pHdrBecome)->value);

// execute "wpSetup" on the new object
rc = RwsCall( &pHdrSetup,
RWSP_MNAM, (ULONG)"wpSetup", // call type


RWSR_ASIS, 0, // return type

2, // nbr of args
RWSI_ASIS, 0, *pNewObj, // new object
RWSI_PSTR, 0, "DEFAULTVIEW=OPEN_RUNNING"); // setup string
if (rc) break;

// lock in the method ptr & save a ptr to arg1's value field
pArg = CALCPROCPTR( pHdrSetup);
pArg->type = RWSP_MPFN;
pSetupObj = &(pArg->pnext->pnext->value);

// execute wpUnlockObject on the new object
rc = RwsCall( &pHdrUnlock,
RWSP_MNAM, (ULONG)"wpUnlockObject", // call type


RWSR_ASIS, 0, // return type
1, // nbr of args

RWSI_ASIS, 0, *pNewObj); // new object
if (rc) break;

// lock in the method ptr & save a ptr to arg1's value field
pArg = CALCPROCPTR( pHdrUnlock);
pArg->type = RWSP_MPFN;
pUnlockObj = &(pArg->pnext->pnext->value);

// perform low-overhead operations on remaining files
for (ctr = 1; ctr < cntFiles; ctr++) {

rc = DosQueryPathInfo( apszFiles[ctr], FIL_STANDARD, &fs3, sizeof(fs3));
if (rc) break;
fs3.attrFile &= ~(FILE_READONLY|FILE_HIDDEN|FILE_SYSTEM);
rc = DosSetPathInfo( apszFiles[ctr], FIL_STANDARD, &fs3, sizeof(fs3), 0);
if (rc) break;

strcpy( pBuf, apszFiles[ctr]);
rc = RwsDispatch( pHdrBecome);
if (rc) break;

*pSetupObj = *pNewObj;
rc = RwsDispatch( pHdrSetup);
if (rc) break;

*pUnlockObj = *pNewObj;
rc = RwsDispatch( pHdrUnlock);
if (rc) break;
}

} while (0);

// free the RWS structs used by the methods in the loop
if (pHdrUnlock)
RwsFreeMem( pHdrUnlock);
if (pHdrSetup)
RwsFreeMem( pHdrSetup);
if (pHdrBecome)
RwsFreeMem( pHdrBecome);

// if we created a C-A-Mgr object, delete it
if (camObj) {
if (pHdr)
RwsFreeMem( pHdr);
pHdr = 0;

RwsCall( &pHdr,
RWSP_MNAMI, (ULONG)"somFree", // call type
RWSR_VOID, 0, // return type
1, // nbr of args
RWSI_ASIS, 0, camObj); // C-A-Mgr object
}

// free the first RWS struct
if (pHdr)
RwsFreeMem( pHdr);

return (rc);
}

/***************************************************************************/

Ilya Zakharevich

unread,
Jul 8, 2008, 10:00:00 PM7/8/08
to
[A complimentary Cc of this posting was NOT [per weedlist] sent to
Rich Walsh
<spamyo...@127.0.0.1>], who wrote in article <brddYgxvE0gm-pn2-MMKi3Fdrd6qT@localhost>:

> The ability to chain methods like that would be my primary reason for
> developing RWS further.

> Below are two implementations of the above: one that's very minimally


> optimized and one where everything is optimized. Not surprisingly,
> the first is pretty straight-forward while the second is ..uhh.. messy.

IMO, the "proper" way to implement such a client/server design is to
embed a tiny "standard" command interpreter in the server, and make
the client send "programs" as strings to interpret in the server.

The interpreter of choice would be Tcl - 15 years ago it would take
about 25K of executable space. Nowadays Tcl grew to a major monster
(comparable to Perl in size; I'm afraid today the interpreter would
take about 1M of executable). I've heard about some newer contenders
(Lua?), but never investigated them further. Maybe somebody else
would be able to comment...

Hope this helps,
Ilya

Rich Walsh

unread,
Jul 9, 2008, 7:39:51 PM7/9/08
to
On Wed, 9 Jul 2008 02:00:00 UTC, Ilya Zakharevich <nospam...@ilyaz.org> wrote:
> Rich Walsh wrote in article <brddYgxvE0gm-pn2-MMKi3Fdrd6qT@localhost>:

> > The ability to chain methods like that would be my primary reason for
> > developing RWS further.
>

> IMO, the "proper" way to implement such a client/server design is to
> embed a tiny "standard" command interpreter in the server, and make
> the client send "programs" as strings to interpret in the server.

If the goal had been a "WPS Command Language", that might have been the
way to go - but it wasn't. The goal was a versatile RPC facility that
is capable of executing _any_ SOM/WPS method or SOM Kernel function
using whatever data/data structures the call requires.

By design, RWS is completely ignorant of what it's actually doing
(i.e. invoking a method using known arguments to accomplish some end).
Its operation is completely mechanical: it only "knows" how to massage
data in & data out (as instructed), and how to invoke methods. I would
think this is the opposite of how a command interpreter is designed.

BTW... since you mention "tiny": RWS's client & server dlls are
roughly 25k each (including the statically linked C RTL), so I think
they merit the "tiny" appellation.

Ilya Zakharevich

unread,
Jul 9, 2008, 8:10:50 PM7/9/08
to
[A complimentary Cc of this posting was NOT [per weedlist] sent to
Rich Walsh
<spamyo...@127.0.0.1>], who wrote in article <brddYgxvE0gm-pn2-8p2YK3suOy3d@localhost>:

> > IMO, the "proper" way to implement such a client/server design is to
> > embed a tiny "standard" command interpreter in the server, and make
> > the client send "programs" as strings to interpret in the server.
>
> If the goal had been a "WPS Command Language", that might have been the
> way to go - but it wasn't. The goal was a versatile RPC facility that
> is capable of executing _any_ SOM/WPS method or SOM Kernel function
> using whatever data/data structures the call requires.

Yes, it WAS. But NOW the discussion is about how to limit
client/server communication overhead. And the solution is to let
client to make server preserve a lot of info, and use the preserved
info in future calls (or loop explicitly).

You can raise a home-grown way to do this; what I suggest is just use
a tested well debugged library to handle the data living in the server.

> By design, RWS is completely ignorant of what it's actually doing
> (i.e. invoking a method using known arguments to accomplish some end).
> Its operation is completely mechanical: it only "knows" how to massage
> data in & data out (as instructed), and how to invoke methods. I would
> think this is the opposite of how a command interpreter is designed.

I do not think so. Even if your command interpreter supports ONE
custom function (e.g., wps_exec()), the way to temporarily store its
return value(s) in the server, and reuse/free the stuff later (using
loops running in the server) would simplify the mess (one we currently
see) a lot.

> BTW... since you mention "tiny": RWS's client & server dlls are
> roughly 25k each (including the statically linked C RTL), so I think
> they merit the "tiny" appellation.

Yes, this is what I suspected. There MUST be a small embeddable
interpreter around...

Yours,
Ilya

Rich Walsh

unread,
Jul 9, 2008, 11:24:01 PM7/9/08
to
An FYI...

I was playing with camBecomeInstanceOf() and found that it works
with folders as well as files. I took a generic folder and changed
it into an instance of MMFolder, WPUrlFolder, WPStartup, & WPDesktop.

In a few cases the WPS crashed but I couldn't identify the exact
circumstances because the same transformation usually caused no
problems when repeated later. I should mention that my config.sys
contains SET SHELLEXCEPTIONHANDLER=OFF. Without this, the WPS
might have handled whatever the problem was more gracefully.

Lars Erdmann

unread,
Jul 11, 2008, 4:13:46 PM7/11/08
to
Hi,

"Rich Walsh" <spamyo...@127.0.0.1> schrieb im Newsbeitrag

news:brddYgxvE0gm-pn2-c8BIQ64GbD1H@localhost...


> An FYI...
>
> I was playing with camBecomeInstanceOf() and found that it works
> with folders as well as files. I took a generic folder and changed
> it into an instance of MMFolder, WPUrlFolder, WPStartup, & WPDesktop.

Yeah, that's funny, the WPS does not offer a user interface to change
folders (WPFolder and derived), only data files (WPDataFile and derived).

>
> In a few cases the WPS crashed but I couldn't identify the exact
> circumstances because the same transformation usually caused no
> problems when repeated later. I should mention that my config.sys
> contains SET SHELLEXCEPTIONHANDLER=OFF. Without this, the WPS
> might have handled whatever the problem was more gracefully.


Maybe that's why they did not offer the user interface for Folders. They
couldn't get it stable with WPFolder ...


P.S.: Many thanks for your sample code.

Lars


Marty

unread,
Jul 11, 2008, 9:38:24 PM7/11/08
to
Lars Erdmann wrote:
> Hi,
>
> "Rich Walsh" <spamyo...@127.0.0.1> schrieb im Newsbeitrag
> news:brddYgxvE0gm-pn2-c8BIQ64GbD1H@localhost...
>
>>In a few cases the WPS crashed but I couldn't identify the exact
>>circumstances because the same transformation usually caused no
>>problems when repeated later. I should mention that my config.sys
>>contains SET SHELLEXCEPTIONHANDLER=OFF. Without this, the WPS
>>might have handled whatever the problem was more gracefully.
>
> Maybe that's why they did not offer the user interface for Folders. They
> couldn't get it stable with WPFolder ...

Not meaning to be overly negative, but the MM Folder class itself was a
bit of a turd when it came to stability, with or without re-classing.

Becoming a URL folder sounds like a strange idea with not very
predictable behavior.

Becoming a desktop and becoming a startup folder could probably be
confusing to the legacy IBM code (although XWorkplace and such handle it
very well).

So I guess I'm not particularly surprised that they didn't fully
implement this code path down to the user level.

--
[Reverse the parts of the e-mail address to reply.]

Rich Walsh

unread,
Jul 11, 2008, 9:38:26 PM7/11/08
to
On Fri, 11 Jul 2008 20:13:46 UTC, "Lars Erdmann" <lars.e...@arcor.de> wrote:
> "Rich Walsh" schrieb im Newsbeitrag news:brddYgxvE0gm-pn2-c8BIQ64GbD1H@localhost...

> > I was playing with camBecomeInstanceOf() and found that it works
> > with folders as well as files.
>

> Yeah, that's funny, the WPS does not offer a user interface to change
> folders (WPFolder and derived), only data files (WPDataFile and derived).

There are only a few classes (e.g. MMFolder & WPUrlFolder) where this
ability even makes sense for the average user. For most system-supplied
subclasses, it would probably be considered dangerous (e.g. WPDesktop).
Still it might be handy to have a utility that could repair your
Desktop or Startup folder.

> P.S.: Many thanks for your sample code.

Creating and discussing it made me realize that RWS could use another
function or two to make optimization cleaner & simpler. While I may
be familiar with its internals, there's no reason why you should have
to know its inner workings to get good results.

BTW... something I failed to mention: In the optimized version,
the primary performance gain occurs on the client side. Not having
to allocate, build, and populate a request structure for every call
probably saves more time than reusing object & method pointers
(though reusing them will certainly improve performance even more).

Lars Erdmann

unread,
Jul 12, 2008, 9:08:48 AM7/12/08
to

"Rich Walsh" <spamyo...@127.0.0.1> schrieb im Newsbeitrag
news:brddYgxvE0gm-pn2-RQgfLHsLdOYw@localhost...

> On Fri, 11 Jul 2008 20:13:46 UTC, "Lars Erdmann" <lars.e...@arcor.de>
> wrote:
>> "Rich Walsh" schrieb im Newsbeitrag
>> news:brddYgxvE0gm-pn2-c8BIQ64GbD1H@localhost...
>
>> > I was playing with camBecomeInstanceOf() and found that it works
>> > with folders as well as files.
>>
>> Yeah, that's funny, the WPS does not offer a user interface to change
>> folders (WPFolder and derived), only data files (WPDataFile and derived).
>
> There are only a few classes (e.g. MMFolder & WPUrlFolder) where this
> ability even makes sense for the average user. For most system-supplied
> subclasses, it would probably be considered dangerous (e.g. WPDesktop).
> Still it might be handy to have a utility that could repair your
> Desktop or Startup folder.

Ok, that's true. You could easily screw up your complete system.

>
>> P.S.: Many thanks for your sample code.
>
> Creating and discussing it made me realize that RWS could use another
> function or two to make optimization cleaner & simpler. While I may
> be familiar with its internals, there's no reason why you should have
> to know its inner workings to get good results.

Yes I also had that feeling, for some things you have a macro, for others,
you have a function etc. On the other hand, it's very stable and powerful
and a lot better then DSOM which seems to have been abandoned even before
SOM. At least, DSOM has some shortcomings that makes it not very suitable to
communicate with WPS objects (SOMObject derived classes might work a lot
better).
Examples: it does not support "somID" as a parameter (that data type cannot
be passed across process borders), it gets confused if you replace WPS
classes (I have XWorkplace installed and all of a sudden, you are not able
to access any WPS object because XWorkplace replaces some pretty fundamental
classes. The same program works fine if you deinstall XWorkplace), you
possibly need to adjust the configuration (interface repository,
implementation repository) in order to get your application to run OK, etc.
The one thing I liked about DSOM was that proxy object concept that allows
you to write code just like for any WPS class. You talk to objects and
that's that ...
RWS is really different but now that I understand how it works, it's also
fine with me ...


> BTW... something I failed to mention: In the optimized version,
> the primary performance gain occurs on the client side. Not having
> to allocate, build, and populate a request structure for every call
> probably saves more time than reusing object & method pointers
> (though reusing them will certainly improve performance even more).


I am not too worried about performance. I just have the problem that my VAC
3.x projects that I backup every now and then always "loose" their
"IWFProject" class and fall back to being of class "WPDataFile". Somehow
this seems to depend on the file type which is saved in the files EAs
("IWFProject" objects have a very distinct file type). So, every now and
then I need to restore those VAC 3.x projects and they are too numerous (or
I am too lazy) to do it by hand. On the other hand I guess I would just need
to preserve their EAs. I just saved those files (because that's what
"IWFProject" objects are physically) to CD-ROM. Maybe I have to dig deeper
into ZIP and see how I can preserve EAs (apart from running something like
EAUTIL).


Lars


Mie

unread,
Jul 12, 2008, 12:46:37 PM7/12/08
to

> Maybe I have to dig deeper into ZIP and see how I can preserve EAs
> (apart from running something like EAUTIL).

YMMV, but LH32.EXE (in LH2* @ Hobbes?) is rather easy to use, with a
limited number of switches. E.g.:

LH32.EXE a Projects.LZH D:\Projects\* /e /a /s

You'll need to replace the "a"(dd) with an "x" to extract, and this is
a help for remembering the (also ea-related) switches: "/e /a /s"

---

0 new messages