Some time ago, I wrote a barcode scanner NPAPI plugin for the HTML5 browser by zetakey. It is based on code supplied as MySensor in the motorola knowledge base. The plugin is for Windows Mobile 6.x based devices by Intermec and another one for M3 devices.
The MySensor plugin based on npruntime was the only sample I could get to compile and work correctly. The barcode scanner fork I wrote does also work very well. The new MyDevinfo plugin retrieves model code, battery level and WLAN RSSI value of the Intermec device and allows to present this information to an HTML5 browser user when needed.
The above shows the web page of MyDevinfo_simple.htm.
A NPAPI plugin for Windows Mobile HTML5 browsers like Zetakey Browser, Intermec Browser, Honeywell Enterprise Browser, Honeywell HTML5 Browser or Motorola/Zebra RhoMobile Browser is a DLL. The DLL has to be placed in the browser’s plugin directory and then can be used from HTML5 JavaScript code. The code defines which properties, methods and callbacks can be used from JavaScript. When the browser loads the plugin, it queries all known properties of the plugin object. These properties are accessed via NPIdentifier
types:
...
static NPIdentifier sCurrentRSSIValue_id;
static NPIdentifier sCurrentBattery_id;
static NPIdentifier sModelCode_id;
...
CMyDevinfoPlugin::CMyDevinfoPlugin(NPP pNPInstance) :
m_pNPInstance(pNPInstance),
m_pNPStream(NULL),
m_bInitialized(FALSE),
m_pScriptableObject(NULL)
{
DEBUGMSG(1, (L"CMyDevinfoPlugin()...\n"));
pNPInstance->pdata = this;
NPN_SetValue(m_pNPInstance, NPPVpluginWindowBool, false);
sMonitor_id = NPN_GetStringIdentifier("monitor");
sPollInterval_id = NPN_GetStringIdentifier("pollInterval");
sCurrentValue_id = NPN_GetStringIdentifier("currentValue");
sCurrentRSSIValue_id = NPN_GetStringIdentifier("currentRSSIValue");
sCurrentBattery_id = NPN_GetStringIdentifier("currentBatteryLevel");
sModelCode_id = NPN_GetStringIdentifier("modelCode");
NPObject *sWindowObj;
NPN_GetValue(m_pNPInstance, NPNVWindowNPObject, &sWindowObj);
NPObject *mySensorObject =NPN_CreateObject
(m_pNPInstance,GET_NPOBJECT_CLASS(MyDevinfoPluginObject));
NPVariant v;
OBJECT_TO_NPVARIANT(mySensorObject, v);
NPIdentifier n = NPN_GetStringIdentifier("MyDevinfo");
NPN_SetProperty(m_pNPInstance, sWindowObj, n, &v);
NPN_ReleaseObject(mySensorObject);
NPN_ReleaseObject(sWindowObj);
}
In the above, you can see the global initialization of the property and method names for the Devinfo
object. When a property of the JavaScript object is queried, the following code is executed:
bool MyDevinfoPluginObject::GetProperty(NPIdentifier name, NPVariant *result)
{
bool bReturnVal = false;
VOID_TO_NPVARIANT(*result);
if (name == sCurrentRSSIValue_id)
{
this->m_iCurrentRSSIValue=my_getRSSI();
INT32_TO_NPVARIANT(this->m_iCurrentRSSIValue ,
*result); bReturnVal = true;
}
else if (name == sCurrentBattery_id)
{
this->m_iCurrentBatteryLevel=getBatteryPercent();
INT32_TO_NPVARIANT( this->m_iCurrentBatteryLevel,
*result); bReturnVal = true;
}
else if (name == sModelCode_id)
{
char* npOutString = (char *)NPN_MemAlloc(MAX_BUFF);
sprintf(npOutString, "%s", getModelCode());
STRINGZ_TO_NPVARIANT( npOutString ,
*result); bReturnVal = true;
}
if (!bReturnVal)
VOID_TO_NPVARIANT(*result);
return bReturnVal;
}
The return types have to be put in a NPVARIANT
structure which is then returned to the browser. There are different macros to convert int
, float
or null
terminated string
s to a NPVARIANT
.
In the code, I used separate header and code files to retrieve the information like the battery or RSSI level. This is easy to manage.
If you want to extend the number of properties, you need to add a new global NPIdentifier
variable, add code to register the new property and code to return the new property value.
The code for an object method is similar. There is also a global variable of type NPIdentifier
. Then, when the object method is called from JavaScript, the following code is executed:
...
bool MyDevinfoPluginObject::Invoke(NPIdentifier name, const NPVariant *args,
uint32_t argCount, NPVariant *result)
{
bool bReturnVal = false;
VOID_TO_NPVARIANT(*result);
char* szNameCmp = _strlwr(NPN_UTF8FromIdentifier(name));
NPIdentifier methodName = NPN_GetStringIdentifier(szNameCmp);
NPN_MemFree(szNameCmp);
if (methodName == sMonitor_id)
{
if (argCount == 1 && NPVARIANT_IS_BOOLEAN(args[0]))
{
if (NPVARIANT_TO_BOOLEAN(args[0]))
{
CloseHandle(CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)SensorMonitorThread, this, 0, NULL));
}
else
{
SetEvent(m_hStopSensorMonitor);
}
VOID_TO_NPVARIANT(*result);
bReturnVal = true;
}
}
if (!bReturnVal)
VOID_TO_NPVARIANT(*result);
return bReturnVal;
}
As the monitor
method is to be called with a boolean to start or stop the monitor
, the code will start or stop a background thread. First, the argument passed to the method is tested to be a boolean, then it is converted from the provided NPVARIANT
to a C boolean.
The background thread uses a window handle to the browser to send update messages. These WM_USER
messages are received by an invisible window and its window procedure. That will then invoke a callback method inside the browser context, if available.
The source code and description can be found at github.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.