A Note For New RFID Projects

If you are developing new RFID software with Nordic ID products, you should use the NUR API. The MHL API is a general handterminal hardware API, and while it is possible to make the same RFID software using MHL, you will get more performace with less code with the NUR API. The NUR API will also yield code that is easier to read, and more suitable to the task of high performance RFID. Note that the NUR API is only available for devices that actually have the NUR module. Most UHF devices produced in 2012 are NUR devices, except 100 mW UHF Morphics and devices specifically ordered with the ThingMagic module. 

Nordic ID Multiple Hardware Layers [MHL]

MHL is a service running on Nordic ID handterminals that provides hardware control services to applications. It's role is  the same as Application Programming Interface (API) libraries in other manufacturers devices. This help is intended for the Nordic ID Morphic and Merlin handterminals from 2011 onwards. If you have a newer unit this help is likely useful, but for the older PL3000 and PL2000 please refer to their manuals & support pages. 

How is it different from a typical API?

It is a service, not a DLL. So when you read from and write to it, you are actually making service calls and talking to the device drivers. A typical API is a DLL which you link to at compile time. This has the disadvantage often called DLL hell, where updating or changing the DLL will break your software. If a function is missing in MHL it will always gracefully fail, with an error response, not by throwing a fatal exception. You don't actually need to do service calls explicitly, we have created mhl.h to make using MHL easier. It presents to you an API like interface that hides all the service and driver calls.    

The only unusual bit you need to get used to is that actual functions are never called, you always call function by their string name. You use functions like GetInt, GetBool and GetString with the name of the actual feature function as a parameter. This is a bit inefficient in terms of speed and clarity, but it means your program never crashes because of updates or changes to the hardware or MHL drivers. The basic MHL functions themselves almost never change, and if they do it is to add a new one. So your program will always run in a newer version of a Nordic ID unit, provided you properly check the return values of the MHL functions. If you assume that hardware components exist, and do not check the return values it will be as error prone as any other API.

MHL Block Diagram

MHL Block Diagram

What do I need?

For  .NET Compact Framework 2.0 (Visual Studio 2005 & 2008)

You need the .NET wrapper class version 2.0 or 3.0. It is also recommended, but not mandatory to install the SDK for Visual Studio 2005.  If you have an SDK for another ARMV4i unit running Windows CE 6.0 you can use that SDK. You can also target the Morphic with the Merlin SDK and vice versa. The universal Windows CE 5.0 SDK can also be used.

Note that when you install the SDK and you only have VS2008 installed, you must deselect the help items in the installer. The installation will fail otherwise. If you have both VS2005 and VS2008 installed, you can install everything.

For .NET Compact Framework 3.5 (Visual Studio 2008)

Compact Famework 3.5 is not present by default in Nordic ID's Windows CE 6.0 units, so you must have the Customizer packet that contains CF3.5 installed in your unit. Other than that the requirements are the same as above.

For native C/C++ applications (Visual Studio 2005 & 2008)

You need to have the SDK installed so that the compiler correctly targets the ARMV4i Windows CE 6.0 platform. Additionally you need mhl.h to use MHL. Since MHL is a service you do not need any DLL files or libraries to link against. 

For Java applications

You need to have a Java Virtual Machine running on your unit. Nordic ID has some experience with both Creme and IBM J9, you can use either or any other JVM you manage to get running. Nordic ID has created an MHL wrapper class for Java using JNI that you can use in order to use MHL in your application.

For Internet Explorer client side scripting

Nordic ID has created a COM component that is registered to the browser by default. This means you can make MHL calls in client side scripts running on Internet Explorer in the unit. Note that JScript  does not do pointers so using GetBin and SetBin is not possible.

MHL Downloads


These are intended for Visual Studio 2005, but you can install them with 2008 as long as you uncheck the documentation. If you have both VS2005 and VS2008, you should have no problem installing the documentation as well. 

Morphic SDK

Merlin SDK

.NET Compact Framework MHL Wrapper with Demo Code

These projects contain a Wrapper class that hides the ugly bits of calling native code. They also contain sample projects that demonstrate how to use MHL trough the wrapper class.

MHL Wrapper v.2 for Visual Studio 2005

Contains the wrapper class, demo projects, scan helper and a demo project for the scan helper class.

MHL Wrapper v.2 for Visual Studio 2008

Contains the wrapper class and demo projects

MHL Wrapper v.3 for Visual Studio 2005

Contains a new wrapper class that encapsulates the MHL Handle, making it easier to use and prettier code. Also integrated are the ScanHelper, Win32 API Error Codes and Error Code Strings. The file contains the same demo projects as in the v.2 wrapper project, but they have been changed to use this new wrapper. 

MHL Wrapper v.3 for Visual Studio 2005, Compiled October 2012

There is no difference in MHL functionality between this version and the one above, but the C# wrapper also contains WIN32 API PInvoke definitions that Nordic ID uses internally extensively. You are free to use these, but they are not documented. This version has more WIN32 API functions readily PInvoked in the wrapper, compared to the 2011 version above. 

MHL Wrapper v.3 for Visual Studio 2008, Compiled October 2012

This is the same project as the one above, but converted to Visual Studio 2008.  Nordic ID uses the Visual Studio 2005 version internally, even when developing applications in 2008. There is no functional difference exept for the project files.  


MHL Header

Header file for working with MHL. No .DLL or .LIB needed, these are service calls. 


Java MHL wrapper

MHL Basics

MHL functionality can be thought of as consisting of four parts: Get functions, Set functions, profile management and enumeration functions. The actual functions are documented separately for each language or environment because their signature is different depending on the language used. Please see the MHL Base C/C++, .NET Wrapper, Java Wrapper or COM Wrapper documentation depending on which environment you will be using. 

Get/Set Functions

These are the functions you use to actually query and command the MHL feature functions. There is one Get/Set function pair per data type supported by MHL. Data types currently supported are boolean, integer, unsigned integer (DWORD), string, 64 bit floating point (double) and byte blocks (GetBin/SetBin). 

Profile Management

The MHL Feature Drivers typically have functions whose setting can be stored in a profile. Not all features are stored in a profile. An example of a feature function that does not go in the profile is Scanner.Scan. This function triggers barcode reading and therefore does not represent a configurable setting. The function Scanner.TriggenMode is an example of a function whose setting can be stored in a profile as it does not trigger a hardware function but instead cofigures how the scanner should behave when triggered.

The initial reason for creating profiles was to allow applications to take full control of the unit's keyboard and barcode scanner when running, yet they should be able to easily restore the factory default setup upon exiting. This is what the profiles are typically used for. When an application starts, the existing setup is stored in a temporary profile and any needed changes to the current setup are made. When the application exits it loads the temporary profile, thereby restoring the device to the state it was before the app started. 

Enumeration Functions

These functions are typically not used by application programmers. They enumerate the drivers and functions available in MHL itself, dynamically at runtime. The NID Scanner  Control Panel applet is an example of an application that uses these. It dynamically queries the scanner driver for available barcode types and populates the barcode enable / disable list. The enumeration functions are only needed for this kind of use, and should not be needed at all by a typical application. For this reason these functions are not implemented in the wrapper classes. Should you need these functions it is fairly trivial to extend the wrapper projects yourself to include them.

MHL Datatypes


This data type is internally made up of 16-bit unsigned integers, all strings being null terminated (with the value 0x0000). The string format is the same as Windows CE uses, and usually contains UCS-2 Unicode strings. It is important to understand the difference between character encoding and font. The encoding method used here (UCS-2) can represent all Unicode characters in existence. Since there are more than 65536 Unicode characters in existence, it may take more than one 16-bit integer to encode one character. But they can all be encoded, so the operating system will internally handle all character sets defined in Unicode. 

A completely different issue is whether you can see the character on the screen or not. That is a problem of fonts, not character encoding. You must have a font file registered in the unit that contains a visual representation of the character to be shown in order to actually have a character drawn out. Nordic ID units typically contain all fonts needed in Europe, including Cyrillic. Typically absent because of the space they take are all middle and far eastern fonts, and Hebrew. These may be available as a Customizer packet, in which case you can get the font installed even tough it is not part of the factory setup. Contact Nordic ID support for more information. 

To summarize: The operating system and MHL understands all character encodings defined in Unicode (including far eastern, middle eastern and hebrew), but wheter it can display them or not depends on if there are suitable fonts installed. 

String  in .NET, Java & trough COM.
The string data type is internally cast to a suitable format in the wrapper classes provided above. For .NET this means the String class, which is not NULL terminated. The COM component uses the same wide character null terminated string format as MHL, altough the data type definition is a BSTR. In Java the String class is used to represent strings.

NOTE: All lengths when dealing with the String data type are wide character lengths (16-bit units), not byte lengths. The NULL character is not included in the lengths.


This data type is used to handle raw chunks of data, it is made up of unsigned bytes. The data may have an internal structure depending on the MHL Feature function used, but MHL assumes it has none. It is treated as a chunk of data, and no modifying or error checking is done to it. It is copied straight from the MHL Feature Driver to the user application memory buffers, or vice versa. In .NET the byte array data type is used to contain the data, as its internal representation is very close to actual raw bytes. The same goes for the Java wrapper. The COM component is a special case. It was created to allow end users to use MHL in Internet Explorer client side scripts. Those scripts (JScript and VBScript) do not support pointers, so there is no way to actually represent the data in those languages. For this reason the COM component does not contain the GetBin and SetBin functions. 


The name of this data type is historical at this point. The WORD data type used to mean the size of the processors registers, when used in the C language compiler made for that processor. The double word was twice that size. Since the DWORD has for a very long time been a 32 bit unsigned interger, it has kind of solidified into always meaning a 32 bit unsigned integer. So even though most of todays processors are 64 bit (and correspondingly have a 64 bit word), the DWORD data type designates an unsigned 32 bit integer in most Windows programming environments. This is also true for MHL. All the wrappers to other languages leave these values unchanged as there is a corresponding native type in those languages. .NET uses the uint, Java has the int and COM uses the long (int and long are signed, but the binary content remains the same). 


This data type is the same 32-bit size as the DWORD, but it is signed. In the .NET and Java wrappers, it is represented by the int datatype. In the COM wrapper, it is represented by the long datatype.


While this data type represents a true or false value and thus only has two states it is based on the WIN32 API BOOL datatype. This in turn is a 32 bit unsigned integer. The MHL boolean is also a 32 bit unsigned integer. It is defined so that zero means false and all other values mean true. When setting the value using SetBool the input range is checked, and must be either zero or one. Both .NET and Java have native boolean data types, these are used to represent the MHL boolean trough those wrappers. In COM the WIN32 API BOOL is used. 

Mandatory Bits

The information in this Document is subject to change. Nordic ID assumes no responsibility regarding the information presented in this Guide.


Nordic ID Oy owns all rights to this document. All rights reserved. Copying this document without the written permission from the manufacturer by printing, copying, recording or by any other means or the full or partial translation of the manual to any other language including all programming languages using any electrical, mechanical, magnetic, optical, manual or other methods or devices is forbidden.
Nordic ID reserves the right to change the technical specifications or functions of its products or to discontinue manufacturing of any of its products without any written announcement and urges customers to ensure that the information at their disposal is valid.


Nordic ID products have not been designed, intended nor inspected to be used in any life support related applications nor as a part of any other critical system and are not granted functional warranty if used in any such applications.
Nordic ID urges its customers to arrange proper and adequate user training, which includes safety issues for any personnel using, programming or otherwise handling Nordic ID products.


Nordic ID and the Nordic ID logo are registered trademarks of Nordic ID Oy.
All terms mentioned in this document that are known to be trademarks or service marks have been appropriately marked in the list below with either the ©, ® or the ™ symbol or started with capital letter. Nordic ID cannot attest to the accuracy of this information. Use of a term in this document should not be regarded as affecting the validity of any trademark or copyright.

MHL Manual in PDF form

These PDF files are autogenerated by a PHP script from the contents of the MHL function database. The contents of the manual will therefore exactly match what is on this website at the date of generation.

MHL Documentation 14.02.2011


Show current driver on every function documentation page.
PHP strip_tags implemented WWAN driver descriptions. Should remove some of the unnecessary blank space in the descriptions.


Fixed clumped together input value documentation

Integer GetLastError() - Changed to read only

DWORD Keyboard.InputMode - Fixed Tiny Text
DWORD Keyboard.ScanMode - Fixed Tiny Text

String MHL_GetBool(HANDLE hDrv, const TCHAR *name) - Changed to ReadOnly
String MHL_OpenDrv(const TCHAR *drv) - Changed to ReadOnly

DWORD Utility.ResetDevice - Changed to WriteOnly
Utility.PlaySound - Added undocumented Function
Utility.PlaySoundSync - Added undocumented Function
Utility.PlaySoundStop - Added undocumented Function
Bluetooth.Power - Added undocumented Function
Wlan.Power - Added undocumented Function
Utility.FlashRegistry - Added undocumented Function
Utility.DeepSleep - Added undocumented Function

Code Samples
Made code sample font one step larger

MHL Documentation 09.02.2011

Initial Version

Didn't find what you were looking for?

LinkedIn Search