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