How I write my WPS Objects

From EDM2
Jump to: navigation, search

By Mindy Pollack

This is how I write my WPS objects:

1. I find an object already written. You can use the car sample.

2. Think of a name for your class. If it is going to just do stuff for you you could call it Worker or WorkerClass or whatever you want. You should probably use your app name somewhere in there. Also come up with a file name and is <= 8 chars like worker.

3. Copy car files to new directory off toolkt21\c\samples\ Rename all Car file names to Worker.

4. edit worker.csc. This is the SOM definition file. Look at the toolkit pub for info on the parts of the SOM definition file. change all references to Car to your class. change the external prefix, etc. Also change the parent class. Your object should probably inherit from WPAbstract. (wpabs.sc) To start simple, take out passthru statements, take out instance data (you can add some later if you need it), take out new methods (release order and method defines that don't say override).

5. Add or remove methods you want to override. Methods that start with wp are instance methods and those starting with wpcls are class methods. Look at the docs or the comments in car.c for info on what the methods do. You'll get better results if you just ask here. There isn't any good docs on it yet (I'm working on it).

6. You should override wpSetup for IPC with your other program (assuming you're still going to have another program). You can make up your own key name like APPWINDOW= and give the window handle and then use messages and/or DDE to communicate back and forth. The object can create an invisible window to handle the object's communication end.

7. edit makefile and change stuff. Delete the .def file and SOM will create one as long as .def is included in the things to build in the sc command. (check SMEMIT and put in .def) or just edit worker.def and change Car to the class name and change the library name.

8. rename the .C file to something else because it is full of Car class stuff and you want SOM to generate a new one that will have stuff for your class. compile. When icc starts, hit ctrl+c because SOM generated the .C file but you have to edit it to add the code you need.

9. Add code to the .C file. When you need a new method, or method override or instance data, add it to the .csc file and recompile. SOM will add the method call to the bottom of your .C file. BEWARE: SOM will #define SOM_CurrentClass to be either your class or your metaclass at different sections of the .C file for the instance methods and the class methods.

When you recompile and SOM adds new methods to the bottom, if they are instance methods they will be out of place and you will have to move them to the area in the code where the other instance methods are. (otherwise you will pull your hair out very often)

10. replace SOMOutCharRoutine with your own (see SOM prog guide in toolkit) so you can use SOMMethodDebug. somMethodDebug will call somPrintf which calls SOMOutCharRoutine for every character outputted. By default it will goto stdout (very useful in PM...NOT!). have it output to a file so you can see the flow of the code. I've never done this so maybe someone else can help you out with it. Make sure you don't ship your product with the SOMOutCharRoutine replaced because only one can exist for each process and you are sharing the process with other WPS apps. (not very friendly to hinder someone else's debugging)

11. Let's see what else??? Be patient and ask as many questions you want on the developer forum.

12. put the .DLL in the LIBPATH, register the class with workplace, and create an object. REXX code snippet:

 /* Register a Workplace class  */
 
 /* Load the REXX utility functions  */
 call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
 call SysLoadFuncs
 
 /* Register new class with Shell */
 
 result = SysRegisterObjectClass("MyClass", "MYCLASS")
 if result
      then say 'Class registration successfully completed'
      else say 'SysRegisterObjectClass failed.  RC =' result

 rc = SysCreateObject('MyClass', 'Test', '<WP_DESKTOP>','OBJECTID=<TEST>',,
       'ReplaceIfExists');

 if rc = 1 then
    say 'object created successfully'
 else
    say 'object not created successfully'

Here's some code for find:

This function is a thread (thus the message queue) It finds all the printer objects off the desktop tree and, if found, sets the local printer to the default. Not useful but gets the point across.

 VOID FindPrinterObjects(VOID)
 {
  CLASS   apClass[2];
  HFIND   hFind;
  SOMAny  *Desktop, **pBuffer;
  BOOL    bReturn;
  ULONG   ulError = 0, ulCount = 10;
  HMQ    hmq = 0;
  HAB    hab = 0;

  hab = WinInitialize(0);
  if (!hab)
     return;

  /* workplace threads need message queues */
  hmq = WinCreateMsgQueue(hab, 0);
  if (hmq)
     WinCancelShutdown(hmq, TRUE);
  else
  {
     WinTerminate(hab);
     return;
  }

 /* array of classes.  only one at a time works */
  apClass[0] = _WPPrinter;
  apClass[1] = NULL;

  /* get desktop object */
  Desktop = _wpclsQueryFolder(_WPObject, "<WP_DESKTOP>", FALSE);
  if (Desktop)
  {
     /* alloc buffer */
     pBuffer = malloc(sizeof(SOMAny *) * ulCount);
     if (pBuffer)
     {
        _wpclsSetError(_WPObject, 0);

        /* start the find */
        bReturn = _wpclsFindObjectFirst(_WPObject, apClass, &hFind, "*",
                                      Desktop, TRUE, NULL, pBuffer, &ulCount);
        if (!bReturn)
           ulError = _wpclsQueryError(_WPObject);

        if (!ulError || ulError == WPERR_BUFFER_OVERFLOW)
        {
           ProcessBuffer(pBuffer, ulCount);

           /* loop for more: bug-> ulError could be overflow when ulCount
            * is zero.  (should be WPERR_OBJECT_NOT_FOUND)
            */
           while (ulCount && ulError == WPERR_BUFFER_OVERFLOW)
           {
              ulError = 0;
              ulCount = 10;

              _wpclsSetError(_WPObject, 0);
              bReturn = _wpclsFindObjectNext(_WPObject, hFind, pBuffer,
                                             &ulCount);

              if (!bReturn)
                 ulError = _wpclsQueryError(_WPObject);

              if (!ulError || ulError == WPERR_BUFFER_OVERFLOW)
              {
                 ProcessBuffer(pBuffer, ulCount);
              }
           }
           /* all done.  close find */
           _wpclsFindObjectEnd(_WPObject, hFind);
        }
        free(pBuffer);
     }
  }

  WinDestroyMsgQueue(hmq);

  WinTerminate(hab);
 }


 VOID ProcessBuffer(SOMAny **pBuffer, ULONG ulCount)
 {
  ULONG i;
  CHAR  szMessage[256];
  PSZ   pszTitle;
  FILE  *fpFile;

  for (i = 0; i < ulCount; i++)
   {
     if (_wpQueryComputerName(pBuffer[i], szMessage) == 1 )
     {
        _wpSetDefaultPrinter(pBuffer[i]);
     }
     /* you must unlock each object because workplace locks them
      * when doing a find.
      */
     _wpUnlockObject(pBuffer[i]);
   }
 }

By Mindy Pollack id: 74047.2731