r22 - 29 Nov 2005 - 11:16:55 - GuilhermeCHazanYou are here: SuperWaba >  Codev Web  > BuildingLibraries
stack of books

Libraries - Why Build One?

Libraries may be required for several reasons:

  • To provide access to device-specific functions from SuperWaba.
  • To speed up critical sections of code by writing them in native form.
  • To share a common but large function between applications.
  • To use LGPL'd code in a prorietary application.
  • To put saleable code into a module that can be used by many clients.

Ingredients:

  • The SuperWabaSDK
  • There's a library tutorial available inside the "SuperWaba Companion.pdf" file for the subscribers of the Professional version. If you're a subscriber, check the "Library tutorial" inside the pdf.
  • The usual compilers and Java tools for the platforms you are building for.
  • Creator ID if developing for Palm (get it from http://spp.palmos.com/iws/logon.jsp)

Turning A Java Package Or Class Into A Library

This is a relatively easy process (hey, I managed it) and allows you to use LGPL'd classes with proprietary code. Let's take the "MessageBoxChunky" class as an example (available from the Free stuff area). First, we put the MessageBoxChunky.java file in a directory appropriate for the package structure that we're using (we're using nz/co/econz/superwaba/messageboxchunky because it is in our company's coding rules). If you're not using a package structure, just try not to mix it with any other source code and put it in a directory of its own.

Add the "package" definition to the top of the MessageBox.java file before the usual imports:

package nz.co.econz.superwaba.messageboxchunky;

import waba.fx.*;
import waba.sys.*;
import waba.ui.*;
import waba.util.*;

Compile the package with javac (actual parameters used in our build), followed by creating the .jar file in the usual way:

    [javac] Compilation arguments:
    [javac] '-d'
    [javac] '/home/vik/src/nads/src/WabaClient/eService/classes/MessageBoxChunky
'
    [javac] '-classpath'
    [javac] '/home/vik/src/nads/src/WabaClient/eService/classes/MessageBoxChunky
:/home/vik/src/SuperWabaSDK.421b/lib/SuperWaba.jar'
    [javac] '-sourcepath'
    [javac] '/home/vik/src/nads/src/WabaClient/eService/src:/home/vik/src/nads/s
rc/WabaClient/eService/generated'
    [javac] '-target'
    [javac] '1.1'
    [javac] '-g:none'
    [javac] 
    [javac] The ' characters around the executable and arguments are
    [javac] not part of the command.
    [javac] File to be compiled:
    [javac]     /home/vik/src/nads/src/WabaClient/eService/src/nz/co/econz/super
waba/messageboxchunky/MessageBoxChunky.java

Jar build details are as per the build.xml in the SDK. Now you build the Warp'd PDB file as a global library:

Warp c /t /c SWAB /lg MessageBoxChunky MessageBoxChunky.jar

Put the resulting PDB in the SuperWaba directory on a PocketPC device, or load it into a Palm and it should now work when you reference it with:

import nz.co.econz.superwaba.messageboxchunky.MessageBoxChunky;

Making A Native Library

First, try building the PalmOS Scanner libraries - if you're planning to build for PalmOS. If you can't build them, you know you're on the wrong track.

We found that we had to include headers from Codewarrior's "Other SDKs" section that were device-specific.

It is also important to make sure that you are using the correct SWLib.c and SWLib.h, and this is best done by ensuring the project's include paths are set and in the right order.

At this point, we encountered an error saying:

__RuntimeModule__: 'scannerInstall' referenced from '__DummyStartup__' is
undefined.
which turned out to be the "Entry Point" being set to scannerInstall in the "68K Target" section of our Codewarrior settings. We're not sure why it was set, but if you get the urge to fill in that field, lie down in a darkened room until the feeling goes away.

Once that compiles, follow Guich's tutorial. I know, you want all the details posted here. Well, there's only one of me and I'm short on resources so if anyone feels like contributing, that would be nice. I'm concentrating mostly on PalmOS libraries here and some WinCE input would be good.

Making a Hash of It

To save laborious string compares when looking for function names, SuperWaba narrows things down with a "hash" - a kind of rough index. There might be several entries with the same "hash", but it is better than searching the whole lot.

To clue in the SuperWaba engine, you create a text file containing the path of the library and the definition of its methods - specify the path for any exotic parameters too. This is from the ECONZ RAS dialing library's Ras.txt :

nz/co/econz/superwaba/ras/Ras|static int dial( String phonebookEntry, String user, String password )
nz/co/econz/superwaba/ras/Ras|static int hangup()

You turn this into a methodshash text file like this:

java -classpath /SuperWabaSDK/utils/xplat/MethodsHash MethodsHash Ras.txt

If you're using Windows or a Cygwin terminal you may have to specify the drive letter in the classpath too.

If your hashes are wrong for any reason, you will find debug trace in your SuperWaba Debug Console that includes the has it is looking for - so you can check the values in methodshash.txt next time you rebuild the file and make sure that they match. Typical reasons for a mismatch include: Specifying or not specifying the classpath of a package, starting the method name with a capital letter, and prefixing method names with the library name.

Required Bits

Palm users must put the Creator ID, library name and HASHSIZE (from methodshash.txt) in your own copy of the CustomLib.h file and in the PalmRez Post Linker's Creator field in Codewarrior. If you inadvertently use the same ID for two libraries, SuperWaba gets very confused and fails to find the hash entries because it looks in the wrong file. That one kept me occupied for a day...

Moving on, you need a few defines and includes at the top of your main .C file:

#define BUILDING_CUSTOM_LIB // must be defined prior to include superwaba.h
#define PALMOS 1
#include "superwaba.h"
#ifdef __SWNATIVE_CUSTOM_LIB_H
You included the wrong CustomLib.h file. Be sure it is NOT SWNatives\CustomLib.h.
#endif

You'll want prototypes for your functions like these:

// (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI[I)I
Var WabaRasDial(Var stack[]); 
Var WabaRasHangup(Var stack[]); // (I)V

and you'll need the hash values from the methodshash text file that you got when building the native methods as per Guich's instructions:

uint32 nativeHashes[3] =
{
/* nz/co/econz/superwaba/ras/Ras_Dial_
 *(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I */
3197994301,  
/* nz/co/econz/superwaba/ras/Ras_Hangup_()I */
3198011209,
0  // Must end with 0
};

Before you put in your own functions, you'll need the following routines to make sure your functions can be found:

Err callPublic(int index, uint32 *ret, uint32 *args)
{
   /* !!! Example of implementation for callPublic:
   switch (index)
   {
      case PUBLIC_DummyFunc  : *ret = dummyFunc();      break;
      case PUBLIC_DummyFunc2 : dummyFunc2((int)*args);  break;
   }
   */
   return 0;
}

ClassHook *getClassHooks() {
   return 0; // dunno how to use classhooks...
}

/* Build at runtime the nativeFuncs array */
NativeFunc nativeFuncs[ HASHSIZE + 1 ];
void buildNativeFuncArray() {
   nativeFuncs[  0] = WabaRasDial;
   nativeFuncs[  1] = WabaRasHangup;
   nativeFuncs[  2] = 0;  /* Must end with 0 */
}

/* Called by the vm to let the native libraries handle particular events.
 * Must return SWErrEventHandled or SWErrEventNotHandled. */
Err handleEvent(EventPtr eventP) {
   return SWErrEventNotHandled; /* This event is not my problem */
}

/* Called when this lib is about to be closed.
 * The library must free any allocated resources. */
void onClose() {
   /* Any library-destruction code goes here */
}

Now you can write your own additions.

Passing Parameters

Parameters are passed on the stack, and the parameters are not in 'C'-friendly format - you have to manipulate them. Strings are particularly tricky as they are in Unicode, not in 8-bit ASCII with null terminations as embedded 'C' programmers are used to. Functions are provided for all manner of conversion in SuperWabaSDK/vm/superwaba.c and you invoke them in your code as per this example:

   Var v;
   UtfString phoneUtf;
   char phoneNum[64];
   
   phoneUtf = (vmGlobals->stringToUtf)(stack[ 0 ].obj,STU_USE_STATIC|STU_NULL_TERMINATE);

   (vmGlobals->printToBuf)(phoneNum,sizeof(phoneNum),&phoneUtf,NULL);

   (vmGlobals->debug)(phoneNum);
   v.intValue=PalmRasVoiceCall(phoneNum);
   return v;

Note the debug function. You might need that a fair bit as Codewarrior does not debug libraries. For details on the functions themselves it is currently best to look at the source. A list of all vmGlobals functions is in SuperWabaSDK/vm/superwaba.h . To create more complex debug output, you can use the StrPrintF(buf,format,...) PalmOS? function.

-- VikOlliver - 16 Aug 2004

Returning Values (primitive types)

Normally you will use a native function to do some jobs for you. Maybe calculate something or reading something out of the memory. Therefore you need to pass a result back to your java functions. In the first part I will show you how to pass primitive types back to java. In C nearly everything is an int value. Only floats or 64-bit values work there own way. But let us start step by step. First we create a java class with our methods we want to have in the native part:
import waba.sys.*;
import waba.ui.*;

/**
 * An example for using native methods and return different values to them.
 * 
 * @author Jan Sauerwein
 */
public class Experiment extends MainWindow {
   public native static void voidExperiment();
   public native static boolean booleanExperiment();
   public native static char charExperiment();
   public native static int intExperiment();
   public native static float floatExperiment();
   public native static long longExperiment();
   public native static double doubleExperiment();

   [...]
   
   public void onStart() {
      if(Vm.attachNativeLibrary("ExperimentLib")) {
         Vm.debug("ExperimentLib in use.");
      }
      voidExperiment();
      Vm.debug("returns nothing");
      boolean bEReturn = booleanExperiment();
      Vm.debug("returns " + bEReturn);
      char cEReturn = charExperiment();
      Vm.debug("returns '" + cEReturn + "'");
      int iEReturn = intExperiment();
      Vm.debug("returns '" + iEReturn + "'");
      float fEReturn = floatExperiment();
      Vm.debug("returns " + fEReturn);
      long lEReturn = longExperiment();
      Vm.debug("returns " + lEReturn);
      double dEReturn = doubleExperiment();
      Vm.debug("returns " + dEReturn);

      [...]

      exit(0);
   }
}

You see that I skip the primitive types of byte and short. They are very similar to int so I will explain them there.

Now we have to implement the methods in C. My NativeMethods.txt looks like that:

Experiment|static void voidExperiment()|VoidExperiment
Experiment|static boolean booleanExperiment()|BooleanExperiment
Experiment|static char charExperiment()|CharExperiment
Experiment|static int intExperiment()|IntExperiment
Experiment|static float floatExperiment()|FloatExperiment
Experiment|static long longExperiment()|LongExperiment
Experiment|static double doubleExperiment()|DoubleExperiment

I do not present the whole lib here, only the implementations of the methods. So let us start with some theoretical introduction about the type Var.

typedef union VarT
{
    int32         intValue;
    float32       floatValue;
    void *        classRef;
    uchar *       pc;
    uchar *       oldpc;
    void *        refValue;
    union VarT *  obj;
    unsigned long half64; // guich@200 - added native support for 64 bit doubles and longs - they are stored as 2 consecutives vars
} Var;

Here you can see the types of the Var union. In this first part we will only use intValue, floatValue and the half64. The rest of the varibales I will describe in a part still need to add here. (It is only the time that prevents me from doing so.)

So lets start with the first one:

Var VoidExperiment(Var stack[]) {
   Var v;
   v.obj = 0;
   (*vmGlobals->debug)("voidExperiment():void");
   return v;
}

Ok, returning nothing is not very exciting. Instead of v.obj = 0 you could even use any other type of Var. It also works with an uninitialized variable v but it is more clean to init it.

The next one is even more interesting. boolean. As you have seen in the Var union there is no type for boolean. So you have to do the job with intValue. That works as we are expecting. Everything different from 0 is true, only 0 is false. Here is the code example:

Var BooleanExperiment(Var stack[]) {
   Var v;
   v.intValue = 0; // false
   v.intValue = 1; // true is everything different from 0
   (*vmGlobals->debug)("booleanExperiment():boolean");
   return v;
}

Next we come to the letters. Here I noticed some problems. As you know Java/Superwaba uses UTF-16. So all chars are represented by a 16-bit data type. So I asume the same in the native methods of Superwaba. But it is different. You only have 8-bit chars. Maybe there is someone out there knowing how to send unicode chars back to java. Chars need to be passed also as intValues. There you have 256 chars you can pass. If you use a value bigger than 256 or small er than 0 it is treated as if char is an unsigned integer with 8-bit (UInt8). So you should use such a data type in your C code to make nothing wrong. Here is the code:

Var CharExperiment(Var stack[]) {
   Var v;
   v.intValue = 65; // ASCII-Code for 'A'
   (*vmGlobals->debug)("charExperiment():char");
   return v;
}

The next method is the int one. You can return any int value smaller than 32-bit. If you want to use short or byte you have there limits (Int16 or UInt8).

Var IntExperiment(Var stack[]) {
   Var v;
   v.intValue = 10; // normal 32-bit int
   (*vmGlobals->debug)("intExperiment():int");
   return v;
}

The floating point type need its own representation. As you have seen in Var union there is a floatValue. That you must use to pass a 32-bit foating type.

Var FloatExperiment(Var stack[]) {
   Var v;
   v.floatValue = 3.14; // float 32-bit
   (*vmGlobals->debug)("floatExperiment():float");
   return v;
}

If you are trying to return 64-bit values you will have to do some additional work. You need to push the lower bytes to stack. Here are the both examples.

Var LongExperiment(Var stack[]) {
   // The result must be 5,000,000,000
   Var v;
   vmGlobals->returnedValue2.half64 = 705032704; // (0 - 2^32-1)
   vmGlobals->pushReturnedValue = 2; // stack size
   v.half64 = 1; // =4294967296 (2^32 - 2^64-1)
   (*vmGlobals->debug)("longExperiment():long");
   return v; // returns the upper 32-bit
}

Var DoubleExperiment(Var stack[]) {
   Var v;
   vmGlobals->returnedValue2.half64 = 0; // (0 - 2^32-1)
   vmGlobals->pushReturnedValue = 2; // stack size
   v.half64 = 2147483648; // =0+sign flag (2^32 - 2^64-1)
   v.half64 = 3221225472; // =-2 (2^32 - 2^64-1)
   (*vmGlobals->debug)("doubleExperiment():double");
   return v; // returns the upper 32-bit
}

If you are working with double values, you should know how they work. Cause you need to shift the bits by your own. With long values it is the same but they are easier to understand. I hope this little summary helps you to understand the working of the native methodes. I suggest that you use a MemHandle with the size of 8 bytes to work with the 64-bit types. For the returning you shift (>> 32) or mask (& FFFFFFFF) the result.

-- JanS? - 22 Oct 2004

Setting Up A Microsoft Embedded Visual C++ 4.0 Project

WARNING EVC++ 4.0 Does not yet build working libraries and I've not figured out why. I have documented my progress here in the hope that someone else will pick up on it. For Microsoft platform libraries, EVC 4.0 is a desirable product simply because it is free (see Building The VM for details). It also supports more CPUs than 3.0 such as the ARMV4T, but you do need to select all the ones you want when you create the project. Here's what you do:

  • Create a new AppWizard DLL project, and pick your project name and directory.
  • Select a regular Windows CE DLL without MFC and no automation or sockets (unless you know better).
  • Add CustomLib.h and SuperWabaSDK/vm/ce/SWNatives/SWLib.def to the Headers.
  • Add YourAppHere.c to the Source Files.
  • Under [Project Settings][C/C++] select the Code Generation category.
  • Change "Struct member alignment" to 2 bytes.
  • Select category "Precompiled headers" and tick the Automatic box.
  • Select category "Preprocessor" and clear the "ignore standard include paths" box.
  • Add your application directory to the Additional ones.
  • Then add the SuperWabaSDK/vm/ce, SuperWabaSDK/vm and SuperWabaSDK/vm/ce/SWNatives directories.

You should now be able to compile the DLL. Now, if you can actually get the thing loading, please tell me how you did it!

And Finally

Do not forget to initially load you library with Vm.attachNativeLibrary(libraryName) and check the return value to avoid later embarassment.

There is a lot more to building libraries than this, and Guich's aforementioned tutorial is highly recommended. I do not yet consider myself an expert in building libraries, so feel free to make suggestions and corrections to this document. That's what a Wiki is all about!

-- VikOlliver - 16 Aug 2004

Well not quite "finnaly" -- some news -- Palm OS Developer Suite.

If you are compiling to Palm OS, and want to use PODS (Palm OS Developer Suite), you have to use gcc (even in Windows, with CygWin?). So you have a problem if you use the original examples of SuperWaba, because of the several pieces of ASM (assembly) code, that are in a format not known by gcc. So, as i have a lot work to make one native library (hello world) with PODS, i am attaching a sample (and in the free samples too). Enjoy...

/******************************************************************************
 *
 * Copyright (c) 2004 PalmSource, Inc. All rights reserved.
 *
 * File: SharedLib.c
 *
 * Description:
 *      This is the main source module for a Palm OS shared library.
 *      Based on fine examples from PRC-tools.
 *
 *****************************************************************************/

#include <SystemMgr.h>

#define SHARED_LIB_TRAP(trapNum)   /* Needs to be prior to SharedLib.h inclusion */

#define BUILDING_CUSTOM_LIB // must be defined prior to include superwaba.h
#define PALMOS 1

#include <PalmOS.h>

#include "include/superwaba.h"


#ifdef __SWNATIVE_CUSTOM_LIB_H
You included the wrong CustomLib.h file. Be sure it is NOT the
SWNatives\CustomLib.h.

Specify in the "Access path"
the directory where your CustomLib.h file resides, moving it to the top.

This must be done because a project (like SuperWaba) can have multiple
CustomLib.h files in different directories, and as default the compiler
gets it from the first directory found.
#endif

Var HelloWorldHelloWorld(Var stack[]);

static UInt32 nativeHashes[HASHSIZE + 1];
// build at runtime the nativeFuncs array
NativeFunc nativeFuncs[ HASHSIZE + 1 ];
void buildNativeFuncArray()
{
   nativeHashes[ 0] = 4082418526; // HelloWorld_HelloWorld_()Ljava/lang/String;
   nativeFuncs[  0] = HelloWorldHelloWorld;
   nativeHashes[ 1] = 0;
   nativeFuncs[  1] = 0;  // Must end with 0
}

Err callPublic(int index, UInt32 *ret, UInt32 *args)
{
   /* !!! Example of implementation for callPublic:
   switch (index)
   {
      case PUBLIC_DummyFunc  : *ret = dummyFunc();      break;
      case PUBLIC_DummyFunc2 : dummyFunc2((int)*args);  break;
   }
   */
   return 0;
}

ClassHook *getClassHooks() {
   return 0; // dunno how to use classhooks...
}

/* Called by the vm to let the native libraries handle particular events.
 * Must return SWErrEventHandled or SWErrEventNotHandled. */
Err handleEvent(EventPtr eventP) {
   return SWErrEventNotHandled; /* This event is not my problem */
}

/* Called when this lib is about to be closed.
 * The library must free any allocated resources. */
void onClose() {
   /* Any library-destruction code goes here */
}




typedef struct {
   UInt16 libraryReferenceCount;
} SharedLib_globals;


/***********************************************************************
 *
 * FUNCTION:    start
 *
 * DESCRIPTION: A function all shared libraries must have to patch the
 *             jump table to enable this shared library. 
 *
 ***********************************************************************/

UInt32 start(UInt16 libraryReference, SysLibTblEntryPtr entryP) {
   extern void *jmptable ();
   
   entryP->dispatchTblP = (void *)jmptable;
   entryP->globalsP = NULL;
   
   return errNone;
}

struct htElem
{
    UInt32 key;
    NativeFunc value;
    struct htElem *next;
};

VoidHand hashTableH;
static struct htElem **hashTable;  // guich@400_33

struct VMGlobals *vmGlobals; // setted by the SWInvokeNative


uint16 libRefNum; // our library reference number

/********************************************************************
 * Private functions
 ********************************************************************/
#define htHash(key) (uint16)((key) % HASHSIZE)

/* return the htElem found, else NULL if key doesn't exist */
static struct htElem *htGet(UInt32 key)
{
   struct htElem *np;
   for (np = hashTable[htHash(key)]; np; np = np->next)
      if (np->key == key)
         return np;
   return NULL;
}
/* return struct containing value or NULL if unable to store */
static struct htElem *htPut(UInt32 key, NativeFunc value)
{
   struct htElem *np;
   unsigned hashval;
   if ((np = htGet(key)) == NULL) // duplicated keys not allowed
   {
      np = (struct htElem *) (*vmGlobals->xmalloc) (sizeof(struct htElem));
      if (np != NULL)
      {
          hashval = htHash(key);
          /* point to last w/ this hash */
          np->next = hashTable[hashval];
          np->key = key;
          np->value = value;
          /* attach to hashtab array */
          hashTable[hashval] = np;
      }
   }
   else
      ErrFatalDisplayIf(1, (*vmGlobals->int2str)("**** duplicated key in hashtable ****",key));
   return np;
}

static void disposeHashtable()
{
   // dispose the hashtable
   int i;
   for (i = 0; i < HASHSIZE; i++)
   {
      struct htElem *np;
      np = hashTable[i];
      while (np)
      {
         struct htElem *next;
         next = np->next;
         xfree(np);
         np = next;
      }
      hashTable[i] = NULL;
   }
   MemHandleUnlock(hashTableH);
   MemHandleFree(hashTableH);
}

/***********************************************************************
 *
 * FUNCTION:    SharedLib_Open
 *
 * DESCRIPTION: A function that updates the reference count on how
 *             many applications have the library open. 
 *
 ***********************************************************************/

UInt32 SharedLib_Open(UInt16 libraryReference, void *inGlobalsPtr) {
   SysLibTblEntryPtr entryP = SysLibTblEntry(libraryReference);
   SharedLib_globals* globals = entryP->globalsP;
    ClassHook *libClassHooks;
    int i;
   char buf[60];
      
   /* If no entry, create one */
   if (globals == NULL) {
      entryP->globalsP = MemPtrNew(sizeof(SharedLib_globals));
      globals = entryP->globalsP;
      MemPtrSetOwner(globals, 0);
      globals->libraryReferenceCount = 0;
   }

   /* Increment the references */
     ++globals->libraryReferenceCount;

   ErrFatalDisplayIf(libraryReference == sysInvalidRefNum,"Library not properly loaded!");
   // 1. associate the vmGlobals struct with the given one
   
   vmGlobals = (struct VMGlobals *)inGlobalsPtr;
   // 2. install our hooks
   libClassHooks = getClassHooks();
   if (libClassHooks)
   {
      int hookLibCount = (*vmGlobals->arrayCount)((char *)libClassHooks,sizeof(ClassHook));
      int insertIndex;
      vmGlobals->classHooks = (ClassHook *)(*vmGlobals->expandArray)((char *)vmGlobals->classHooks,sizeof(ClassHook),hookLibCount,&insertIndex);
      if (insertIndex == -1) return SWErrMemory;
      for (i =0; i < hookLibCount; i++)
         libClassHooks[i].libRefnum = libraryReference;

      xmemmove (vmGlobals->classHooks+insertIndex,libClassHooks, hookLibCount*sizeof(ClassHook));
   }
   libRefNum = libraryReference;
   buildNativeFuncArray();
   i = sizeof(struct htElem *) * HASHSIZE;
   hashTableH = MemHandleNew(i);
   
   ErrFatalDisplayIf(!hashTableH,"Not enough memory to allocate hashes");
   hashTable = MemHandleLock(hashTableH); // guich@400_33: we can't use xmalloc because when this library gets unloaded, the object heap is already freed.
   xmemzero(hashTable,i);
   for (i=0; nativeHashes[i]; i++){
      htPut(nativeHashes[i], nativeFuncs[i]);
      xstrprintf(buf,"Funcao %lu colocada em %lu",(UInt32)nativeFuncs[i], (UInt32)nativeHashes[i]);
        (*vmGlobals->debug)(buf);      
   }

   return errNone;
}

/***********************************************************************
 *
 * FUNCTION:    SharedLib_Close
 *
 * DESCRIPTION: A function that decrements the reference count on how
 *             many applications have the library open. 
 *
 ***********************************************************************/

UInt32 SharedLib_Close(UInt16 libraryReference, UInt16* referencesRemaining) {
   
   SysLibTblEntryPtr entryP = SysLibTblEntry(libraryReference);
   SharedLib_globals *globals = entryP->globalsP;

   if (globals == NULL) {
      /* Something went wrong... */
      return 1;
    }
    onClose();
    disposeHashtable();
   
   
    *referencesRemaining = globals->libraryReferenceCount - 1;
  
     /* If no more references free memory */
   if (*referencesRemaining == 0) {
      MemChunkFree (entryP->globalsP);
      entryP->globalsP = NULL;
   }

   return errNone;
}

/***********************************************************************
 *
 * FUNCTION:    SharedLib_Sleep
 *
 * DESCRIPTION: A function needed for handling sleep. 
 *
 ***********************************************************************/

UInt32 SharedLib_Sleep(UInt16 libraryReference)
{
   return errNone;
}
   
/***********************************************************************
 *
 * FUNCTION:    SharedLib_Wake
 *
 * DESCRIPTION: A function needed for handling wake. 
 *
 ***********************************************************************/

UInt32 SharedLib_Wake(UInt16 libraryReference)
{
   return errNone;
}

/************************************************************
 *
 *  FUNCTION: SWLibGetLibAPIVersion
 *
 *  DESCRIPTION:   Get our library API version.  The SW library does not
 *                  need to be "opened" to call SWLibGetLibAPIVersion.
 *
 *  PARAMETERS:   inRefnum      -- SW library reference number
 *                  dwVerP      -- pointer to variable for storing the version number
 *
 *  CALLED BY:      Anyone wishing to get our library API version
 *
 *  RETURNS:      0                  -- no error
 *
 *************************************************************/
UInt32 SWLibGetLibAPIVersion(UInt16 libraryReference, DWordPtr dwVerP)
{
   // Error-check our parameters
   ErrFatalDisplayIf(dwVerP == NULL, "null pointer argument");
   *dwVerP = prvSWLibVersion;
   return errNone;
}

/*************************************************************/
UInt32 SWGetNativeFunc(UInt16 libraryReference, int32 hash, NativeFunc *func)
{
   Err err = errNone;
   struct htElem *elem = htGet(hash);
   if (elem && elem->value)
      *func = elem->value;
   else
   {
      char buf[60];
      xstrprintf(buf,"SWInvokeNativeFunc could not find method with hash %lu",(UInt32)hash);
      (*vmGlobals->debug)(buf);
      
      err = SWErrMethodNotFound;
   }
   return err;
}
/*************************************************************/
UInt32 SWInvokeNativeFunc(UInt16 libraryReference, NativeFunc func, Var stack[])
{
   vmGlobals->returnedValue = func(stack);
   return 0;
}
/*************************************************************/
UInt32 SWInvokeNative(UInt16 libraryReference, int32 hash, Var stack[])
{
   Err err = 0;
   struct htElem *elem = htGet(hash);
   if (elem && elem->value)
      vmGlobals->returnedValue = elem->value(stack);
   else
   {
      char buf[60];
      xstrprintf(buf,"SWInvokeNative could not find method with hash %lu",(UInt32)hash);
      (*vmGlobals->debug)(buf);
      err = SWErrMethodNotFound;
   }
   return err;
}
/*************************************************************/
UInt32 SWCallPublic(UInt16 libraryReference, int index, UInt32 *ret, UInt32 *args)
{
   Err err = callPublic(index, ret, args);
   return err;
}
/*************************************************************/
UInt32 SWHandleEvent(UInt16 libraryReference, EventPtr eventP)
{
   Err err = handleEvent(eventP);
   return err;
}


//////////////////////////////////////////////////////////////////////////
// com/porto/HelloWorld static String helloWorld()
Var HelloWorldHelloWorld(Var stack[]) // ()Ljava/lang/String;
{
   Var v;
   //v.obj = 0;
   char buf [] = "Hello World";
   v.obj = (*vmGlobals->createString)(buf);
   
   // implementation
   return v;
}

/******************************************************************************
 *
 * Copyright (c) 2004 PalmSource, Inc. All rights reserved.
 *
 * File: SWLib.h
 *
 * Description:
 *     This is the header defining the contents of the shared library.
 *
 *****************************************************************************/

#ifndef SHARED_LIB_H
#define SHARED_LIB_H

#include <LibTraps.h>

#define      SWLibTypeID      'libr'      // Standard library database type

#define PUBLIC_subLaunched 987  // Calls this library when a sublaunch occured
                                // with the subscribed launch code (use
                                // (*vmGlobals->registerLaunchCode) to register and
                                // (*vmGlobals->unregisterLaunchCode) to unregister.
                                // This is exclusive for Palm OS.

#include "CustomLib.h"
/* 
 * Note that the following trap number definitions must be evaluated by 
 * the preprocessor using #defines not enum values.  
 */

#define SWLibGetLibAPIVersion_trapNum   sysLibTrapCustom
#define SWInvokeNative_trapNum   sysLibTrapCustom+1
#define SWCallPublic_trapNum   sysLibTrapCustom+2
#define SWHandleEvent_trapNum   sysLibTrapCustom+3
#define SWGetNativeFunc_trapNum   sysLibTrapCustom+4
#define SWInvokeNativeFunc_trapNum   sysLibTrapCustom+5
//#define SharedLib_FunctionA_trapNum   sysLibTrapCustom
//#define SharedLib_FunctionB_trapNum   sysLibTrapCustom

#ifndef SHARED_LIB_TRAP
#define SHARED_LIB_TRAP(trapNum)   SYS_TRAP(trapNum)
#endif


/* Function declarations */

UInt32 SharedLib_Open(UInt16 libraryReference, void *inGlobalsPtr) 
   SHARED_LIB_TRAP(sysLibTrapOpen);

UInt32 SharedLib_Close(UInt16 libraryReference, UInt16 *numAppsP)
   SHARED_LIB_TRAP(sysLibTrapClose);

UInt32  SharedLib_Sleep(UInt16 libraryReference)
   SHARED_LIB_TRAP(sysLibTrapSleep);
   
UInt32 SharedLib_Wake(UInt16 libraryReference)
   SHARED_LIB_TRAP(sysLibTrapWake);


// Get our library API version
UInt32 SWLibGetLibAPIVersion(UInt16 libraryReference, DWordPtr outVersion)   SHARED_LIB_TRAP(SWLibGetLibAPIVersion);
// Invoke the native method
UInt32 SWInvokeNative ( UInt16 libraryReference, int32 hash, Var stack[]) SHARED_LIB_TRAP(SWInvokeNative);
// Invoke a public method
UInt32 SWCallPublic (UInt16 libraryReference, int index, uint32 *ret, uint32 *args) SHARED_LIB_TRAP(SWCallPublic);
// Let the native lib handle events if it want so
UInt32 SWHandleEvent (UInt16 libraryReference, EventPtr eventP) SHARED_LIB_TRAP(SWHandleEvent);
// Gets the NativeFunc given the hash value
UInt32 SWGetNativeFunc(UInt16 libraryReference, int32 hash, NativeFunc *func) SHARED_LIB_TRAP(SWGetNativeFunc);
// Invoke the native method given the native func (faster)
UInt32 SWInvokeNativeFunc(UInt16 libraryReference, NativeFunc func, Var stack[]) SHARED_LIB_TRAP(SWInvokeNativeFunc);

/*
void SharedLib_FunctionA(UInt16 libraryReference, Int32 parameter, Int32* result)
   SHARED_LIB_TRAP(SharedLib_FunctionA_trapNum);
   
void SharedLib_FunctionB(UInt16 libraryReference, Int32 parameter, Int32* result)
   SHARED_LIB_TRAP(SharedLib_FunctionB_trapNum);
*/

#endif

/*********************************************************************************
 *  For the purposes of the SuperWaba software we request that software using    *
 *  or linking to the SuperWaba virtual machine or its libraries display the     *
 *  following notice:                                                            *
 *                                                                               *
 *                   Created with SuperWaba                                      *
 *                  http://www.superwaba.org                                     *
 *                                                                               *
 *  Please see the software license located at SuperWabaSDK/license.txt          *
 *  for more details.                                                            *
 *                                                                               *
 *********************************************************************************/

#ifndef __CUSTOMLIB_H
#define __CUSTOMLIB_H

/********************************************************************
 * Note: you must define the following constants to create your lib *
 ********************************************************************/

#define prvSWLibVersion sysMakeROMVersion(1, 0, 0, 0, 1)

// Library database creator ID - not used in Windows CE
#define         SWLibCreatorID  'SWSL'

// Name of the library - not used in Windows CE
#define         SWLibName       "HelloLib"

/***********************************************************************
 * You can add custom error codes, but don't change those 4 basic ones *
 ***********************************************************************/

// SW Library result codes. Note that appErrorClass is reserved for
// 3rd party apps/libraries, and thus prevents error number collisions
// between PalmOS and libraries.

#define SWErrParam            (appErrorClass | 0)  // invalid parameter
#define SWErrNotOpen          (appErrorClass | 1)  // library is not open
#define SWErrMethodNotFound   (appErrorClass | 2)  // returned from SWInvokeNative if the method is not found in the lib hashtable
#define SWErrMemory           (appErrorClass | 3)  // memory error occurred
#define SWErrEventHandled     (appErrorClass | 4)  // an event was handled by SWHandleEvent
#define SWErrEventNotHandled  (appErrorClass | 5)  // an event was NOT handled by SWHandleEvent

/********************************************************************
 * The following constant define the size of the hashtable. It may  *
 * be a prime number and be larger than the number of functions     *
 * defined in nativeHashes to minimize collisions. The best number  *
 * is computed by the MethodsHash program; just place the output    *
 * here                                                             *
 ********************************************************************/

#define HASHSIZE 1 // (0 collisions) - Insert this value into the CustomLib.h file

/********************************************************************
 * Indexes to be used in the callPublic function       .            *
 ********************************************************************/

// MUST NOT START FROM 0 !
// eg: #define PUBLIC_DummyFunc      1
// eg: #define PUBLIC_DummyFunc2     2
// Object destroyers
// eg: #define PUBLIC_ScannerDestroy 3


/*********************************************************************
 * These array and functions must be implemented by your custom Lib. *
 * See the SuperwabaSDK/vm/palm/SWSymbol for an example.             *
 ********************************************************************/

extern UInt32 nativeHashes[];
extern NativeFunc nativeFuncs[];
void buildNativeFuncArray();

// Called by the Lib when a public method is invoked by the vm or someone else. This defines a interface that lets you add custom methods to interface with the vm without modifying the basic architecture of SW Libs
Err callPublic(int index, UInt32 *ret, UInt32 *args);
// Called by the vm to let the native libraries handle particular events. Must return SWErrEventHandled or SWErrEventNotHandled.
Err handleEvent(EventPtr eventP);
// Called by the system to get the ClassHooks in this custom lib. Must return NULL if no hooks are defined
ClassHook *getClassHooks();
// Called by the system when this lib is about to be closed. The library must free any allocated resources.
void onClose();

#endif

npalm_defines.h

/*********************************************************************************
 *  SuperWaba Virtual Machine, version 4                                         *
 *  Copyright (C) 2000-2004 Guilherme Campos Hazan <support@superwaba.com.br>    *
 *  Copyright (C) 1998, 1999 Wabasoft <www.wabasoft.com>, All Rights Reserved    *
 *                                                                               *
 *  This library and virtual machine is free software; you can redistribute      *
 *  it and/or modify it under the terms of the Amended GNU Lesser General        *
 *  Public License distributed with this software.                               *
 *                                                                               *
 *  This library and virtual machine is distributed in the hope that it will     *
 *  be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of    *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                         *
 *                                                                               *
 *  For the purposes of the SuperWaba software we request that software using    *
 *  or linking to the SuperWaba virtual machine or its libraries display the     *
 *  following notice:                                                            *
 *                                                                               *
 *                   Created with SuperWaba                                      *
 *                  http://www.superwaba.org                                     *
 *                                                                               *
 *  Please see the software license located at SuperWabaSDK/license.txt          *
 *  for more details.                                                            *
 *                                                                               *
 *  You should have received a copy of the License along with this software;     *
 *  if not, write to                                                             *
 *                                                                               *
 *     Guilherme Campos Hazan                                                    *
 *     Av. Nossa Senhora de Copacabana 728 apto 605 - Copacabana                 *
 *     Rio de Janeiro / RJ - Brazil                                              *
 *     Cep: 22050-000                                                            *
 *     E-mail: support@superwaba.com.br                                          *
 *                                                                               *
 *********************************************************************************/

#define ALLOW_ACCESS_TO_INTERNALS_OF_CLIPBOARDS
#define ALLOW_ACCESS_TO_INTERNALS_OF_CONTROLS
#define ALLOW_ACCESS_TO_INTERNALS_OF_FIELDS
#define ALLOW_ACCESS_TO_INTERNALS_OF_FINDPARAMS
#define ALLOW_ACCESS_TO_INTERNALS_OF_FORMS
#define ALLOW_ACCESS_TO_INTERNALS_OF_LISTS
#define ALLOW_ACCESS_TO_INTERNALS_OF_MENUS
#define ALLOW_ACCESS_TO_INTERNALS_OF_PROGRESS
#define ALLOW_ACCESS_TO_INTERNALS_OF_SCROLLBARS
#define ALLOW_ACCESS_TO_INTERNALS_OF_TABLES
#define ALLOW_ACCESS_TO_INTERNALS_OF_BITMAPS
#define ALLOW_ACCESS_TO_INTERNALS_OF_FONTS
#define ALLOW_ACCESS_TO_INTERNALS_OF_WINDOWS

#include <PalmOS.h>                                 // Standard Palm stuff
#include <PalmCompatibility.h>                        // use new headers
#include <SysEvtMgr.h>
#include <SerialMgr.h>
#include <NetMgr.h>
#include <FloatMgr.h>
#include <DLServer.h>
//#include "Screen.h" // Dana support - guich@400_83
//#include "TrgChars.h" // handera jogdial support
//#include "Silk.h" // handera virtual silk support
//#include "vga.h" // handera support
//#include "SonyCLIE.h" // clie support
//#include "waba_res.h"
//#include "PalmChars.h" // FiveWaySDK (see faq)
//#include "PenInputMgr.h"

//#define SUPPORT_HANDERA_HIGHRES // guich note: we cannot support Handera because its virtual keyboard does not support moving to top.

//
// basic types
//

typedef long long int64;
#define uchar unsigned char
#define int32 long
#define uint32 unsigned long
#define float32 float
#define int16 short
#define uint16 unsigned short
#define byte unsigned char

#ifdef PALMOS5
 typedef int32 Pixel;
#else
 typedef byte Pixel;
#endif

typedef union  // added double bits too here
{
   double    d;     // for easy assignment of values
   FlpDouble fd;     // for calling New Floating point manager routines
   uint32    ul[2]; // for accessing upper and lower longs
   int64 ll;
   long l[2];
} Comp64;

#define _inline_ inline

//
// Register definitions for method parameters
//

#define inA0  
#define inA1  
#define inD0  
#define inD1  
#define inD2  

//
// type converters
//

#define getCreator(b) (uint32)( (uint32)((b)[0])<<24 | (uint32)((b)[1])<<16 | (uint32)((b)[2])<<8 | (uint32)((b)[3]) )

static uint32 temp32;
#define getUInt32(b) (uint32)( (uint32)((b)[0])<<24 | (uint32)((b)[1])<<16 | (uint32)((b)[2])<<8 | (uint32)((b)[3]) )
#define getUInt16(b) (uint16)(((b)[0]<<8)|(b)[1])
#define getInt32(b) (int32)( (uint32)((b)[0])<<24 | (uint32)((b)[1])<<16 | (uint32)((b)[2])<<8 | (uint32)((b)[3]) )
#define getInt16(b) (int16)(((b)[0]<<8)|(b)[1])
/*

inline static float32 getFloat32(uchar *buf)
{
   uint32 i;
   float32 f;

   // we need to make sure we're aligned before casting
   i = getUInt32(buf);
   f = *((float32 *)&i);
   return f;
}

static double get64bits(uchar *buf)
{
   FlpCompDouble f;
   f.ul[0] = getInt32(buf);
   f.ul[1] = getInt32(buf+4);

   return f.d;
}

 #define SemaphoreRelease(t) {/*if (vmGlobals->romVersion < 0x05000000)*/ MemSemaphoreRelease(t);}
static int locked=0;
static void lockHeap()
{
   if (locked <= 0)
   {
      SemaphoreReserve(1);
      locked++;
   }
}
static void unlockHeap()
{
//   if (locked)
   {
      SemaphoreRelease(1);
      locked--;
   }
}
#endif

#ifdef PALMOS5
#define GR_ENTER {if (vmGlobals->isHighDensity) WinSetCoordinateSystem(kCoordinatesNative);}
#define GR_EXIT  {if (vmGlobals->isHighDensity) WinSetCoordinateSystem(kCoordinatesStandard);}
#else
#define GR_ENTER
#define GR_EXIT
#endif

//
// x portability functions
//

#define xstrncmp(s1, s2, n) StrNCompare(s1, s2, n)
#define xstrncpy(dst, src, n) StrNCopy(dst, src, (uint32)n)
#define xstrlen(s) StrLen(s)
#define xstrcat(dst, src) StrCat(dst, src)
#define xmemmove(dst, src, size) MemMove(dst, src, size)
#define xmemzero(mem, len) MemSet(mem, len, (Byte)0)
#define xmemset(mem, what, len) MemSet(mem, len, (Byte)what)
#define xstrprintf StrPrintF
#define xstrcaselesscmp StrCaselessCompare
#define xstrstr StrStr
#define xmemcmp MemCmp

#define xfer32(from, to, count) xmemmove(to,from,((count) << 2)) // total of size*4 bytes transfered
#define xzero32(mem,len) xmemzero(mem,((len) << 2))


#if defined(__DEFINE_FUNCTIONS) && !defined(__DONTDEFINE_MEMFUNCS)

   extern DmOpenRef heapDmRef;
   extern int GCCreated;

   void *xmalloc(uint32 size);
   void gc_();
   void debug(char *s);
   char *int2str(char *msg, int32 ii);

   // resizes the ptr. If newSize is smaller than the original size, always successful.
   // Otherwise, may return null if no more memory. Note that the newSize may not
   // be bigger than 64k-32 (PalmOS limit). Returns a ptr with the new size
   // (maybe with different base address)
   // note that this routine does not change where the pointer is allocated.
   // If it was in storage heap, it remains in storage heap; if it was in
   // dynamic heap, it remains in there.
   // if growing, the new area allocated is zeroed out (keeping the old data intact).
   // if p is null, memory is allocated using xmalloc.
   void *xrealloc(void *p, uint32 *newSize);
   void *xrealloc(void *p, uint32 *newSize)
   {
      VoidHand memH;
      uchar *ptr=NULL;
      int firstTry = 1;
      int pos;
      uint32 oldSize=0;
      if (p != NULL)
      {
         ptr = (byte *)p - 2;
         pos = *((int *)ptr);
         ptr = (byte *)ptr - sizeof(VoidHand);
         memH = *((VoidHand *)ptr);
         oldSize = MemHandleSize(memH); // oldsize already includes extra space
         *newSize += sizeof(VoidHand)+2; // new size here does not contain the extra space; add it now
         if (oldSize == *newSize)
            return p; // nothing to do
         if (*newSize > 65500) // too big
            return NULL;
         MemHandleUnlock(memH);
tryAgain:
         #ifdef USE_STORAGE_HEAP
         if (pos >= 0) // storage heap?
         {
            DmReleaseRecord(heapDmRef, pos, 0);
            memH = DmResizeRecord(heapDmRef, pos, (uint32)*newSize); // resize the record to have only 8 bytes
            memH = DmGetRecord(heapDmRef, pos); // andy@340_4: Sets the busy bit for this record.
         }
         else
         #endif
          if (MemHandleResize(memH, *newSize) != 0)
             memH = 0;
         if (!memH)
         {
            if (firstTry && GCCreated) // guich@400_14
            {
               gc_(); // gc may free some memory blocks
               firstTry--;
               goto tryAgain;
            }
            return NULL;
         }
            // locks memory and store again the pointers
         ptr = MemHandleLock(memH);
         *((VoidHand *)ptr) = memH;
         ptr += sizeof(VoidHand);
         *((int *)ptr) = pos;
         ptr += 2;
         if (*newSize > oldSize)
            xmemzero(ptr+oldSize-(sizeof(VoidHand)+2),*newSize-oldSize);
         *newSize -= sizeof(VoidHand)+2;
      }
      else
      {
         ptr = xmalloc(*newSize);
         xmemzero(ptr,*newSize);
      }
      return ptr;
   }
   
   static int32 getNextHeapPos() // guich@421a_66
   {
      int32 i;
      MemHandle h;
      for (i=DmNumRecords(heapDmRef)-1; i >= 0; i--)
         if ((h=DmQueryRecord(heapDmRef,i)) && MemHandleSize(h) == 8)
            DmRemoveRecord(heapDmRef,i);
         else         
            break;
      return i+1;
   }

   void *xmalloc(uint32 size)
   {
      VoidHand memH;
      uchar *ptr;
      int firstTry = 1;
      int pos = -1;
#ifdef USE_STORAGE_HEAP
      UInt upos;
#endif

      // we stick the handle in the first bytes and then return a pointer
      // inside the memory block. Then when we free it, we can get the
      // memory handle back to unlock and free it without having to track it.
      // guich@200b3: we stick also the position of the chunk
      size += sizeof(VoidHand)+2;
tryAgain:
#ifdef USE_STORAGE_HEAP
      if (size >= 1024) // guich@200b3: if size is greater than 1k, alloc space at the storage heap
      {
         pos = getNextHeapPos(); // guich@421a_66: reuse last added records. DmNumRecords(heapDmRef); // add always at the end
         upos = pos;
         memH = DmNewRecord(heapDmRef, &upos, size);
      }
      else
#endif
         memH = MemHandleNew(size);
      if (!memH)
      {
         if (firstTry && GCCreated) // guich@400_14
         {
            gc_(); // gc may free some memory blocks
            firstTry--;
            goto tryAgain;
         }
         return NULL;
      }
      ptr = MemHandleLock(memH);

      // find memory leaks
      // to find a memory leak, you must:
      // 1. get the number that Pose warns
      // 2. put a breakpoint in nmpalm_b.c at SysAppExit
      // 3. when breakpoint is hit, do a "hd 0" in the Palm Debug Console (CodeWarrior)
      // 4. find the handle associated with the number given in 1.
      // 5. Use this handle in the comparision here and set the breakpoint in the "pos" dummy line.
   //   if ((int16)memH == 0x1AF8)
   //      pos = pos * 2 / 2;

      *((VoidHand *)ptr) = memH;
      ptr += sizeof(VoidHand);
      *((int *)ptr) = pos;
      ptr += 2;
      return ptr;
   }
   void xfree_(void *p);
   void xfree_(void *p)
   {
      VoidHand memH;
      uchar *ptr;
      int pos;
      if (p)
      {
         ptr = (byte *)p - 2;
         pos = *((int *)ptr);
         ptr = (byte *)ptr - sizeof(VoidHand);
         memH = *((VoidHand *)ptr);
         MemHandleUnlock(memH);
         #ifdef USE_STORAGE_HEAP
         if (pos >= 0) // storage heap?
         {
            DmReleaseRecord(heapDmRef, pos, 0);
            
            if (pos == (DmNumRecords(heapDmRef)-1)) // guich@421a_66
               DmRemoveRecord(heapDmRef,pos);
            else
               DmResizeRecord(heapDmRef, pos, (uint32)8); // resize the record to have only 8 bytes (we can't resize to 0)
         }
         else
         #endif
            MemHandleFree(memH);
      }
   }
#endif // __DEFINE_FUNCTIONS
-- BigBat? - 27 Feb 2005

toggleopenShow attachmentstogglecloseHide attachments
Topic attachments
I Attachment Action Size Date Who Comment
zipzip palm.zip manage 136.2 K 27 Feb 2005 - 20:33 GregMomm? HelloWorld? Sample
docdoc SW_NativeLib.doc manage 207.0 K 03 Apr 2005 - 04:50 GregMomm?  
Edit | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r22 < r21 < r20 < r19 < r18 | More topic actions
 
SuperWaba home
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding SuperWaba? Send feedback