Omnis Technical Note TNXM0003 June 2009 (Updated October 2019)
Creating Old-Style Unicode External Components (Deprecated)
For Omnis Studio Unicode version
By Gary Ashford
This Technote assumes familiarity with the Omnis
External Component SDK and example projects- which can be downloaded
from this website, and Microsoft Developer Studio/ Visual Studio which
is the Windows application used to compile and link Omnis external components
Please note that old-style external components are deprecated and support for them may be removed in a future edition of Omnis Studio.
Please refer to the Omnis Studio Component SDK for the latest supported technologies, examples and docs.
The following discusses the issues involved when building old-style components compatible with the Unicode version of Omnis Studio. For a discussion relating to new-style components, please refer to Technote TNXM0002
|Old-Style components are self-contained dynamic libraries which reside in the Omnis\external folder. New-Style components are built against the Omnis component library and reside in the Omnis\xcomp folder.|
Unicode or Non-Unicode?
If you are designing a component to be used with both the Unicode and
Non-Unicode versions of Studio (Omnis Studio 4.3.1 for example), you should
create separate Unicode targets, i.e. Unicode Debug
and Unicode Release to complement your existing
Debug and Release
In the Unicode targets, the following additional Preprocessor Definitions are required:
|• isunicode||Requirement of the Omnis external component interface|
|• UNICODE||Requirement of Visual Studio to enable wide character support|
|• _UNICODE||Required by the __T() macro (tchar.h) when creating Unicode literal strings|
In this way, you can make use of conditional compilation statements
(e.g. #ifdef isunicode) to handle Unicode-specific
code whilst retaining the same source files for use by both the Unicode
and non-Unicode targets.
If you will not require the non-Unicode targets (for instance if designing components for Studio 5 and later) the Debug and Release targets can subsequently be discarded. For a full list of preprocessor definitions used by Omnis components, please refer to the sample project properties.
It should be noted that since Studio 5 supports Unicode only, Unicode components are required even if the component itself will ultimately only be handling non-Unicode data.
When building Unicode targets you should ensure that the compiler correctly
recognises the wchar_t data type. With Visual
Studio 2008, the Project Settings->C++->Language>"Treat
wchar_t as Built-in Type" should be set to: No
With Xcode, the following flag should be added to the "Other C++ Flags": -fshort-wchar
Handling Unicode Character data
Omnis Studio uses the Utf32 encoding for all character data exchanged with external components although there are several helper functions and data types which provide compatibility and conversion between other encodings, notably; Utf8 and Utf16. Items common to both old and new-style components are shown highlighted:
(Defined in omstring.h)
|When isunicode is defined, qchar is defined as unsigned long (4 bytes/Utf32). For non-Unicode targets, qchar defaults to unsigned char (1 byte). Most ECO.. and GDI.. component interface methods take qchar arguments as parameters.|
|qoschar datatype||This datatype corresponds to the encoding used by the operating system. qoschar is defined as unsigned short (2 bytes/Utf16) under Windows and MacOSX, but as unsigned char (1 byte/Utf8) under Linux. For non-Unicode targets, qoschar defaults to char. Some external component library classes (notably strxxx) take qoschar arguments in their constructors. See QTEXT()|
|qbyte datatype||qbyte is always defined as unsigned char and is used specifically when handling binary and one-byte-per-character data (i.e. can be used to store Utf8 data if required).|
|QTEXT() macro||This is useful for creating and supplying literal string values
inside components. When _UNICODE is defined, QTEXT() appends the
L ## escape sequence onto the supplied
text. This instructs the compiler to treat the resulting text as
a string of qoschars. QTEXT() can be used anywhere where a qoschar*
argument is required, for example:
qoschar *myText = (qoschar *)QTEXT("Version 188.8.131.52 ");
|QBYTELEN() & QOSBYTELEN() macros||These provide a simple conversion from a supplied character length to the corresponding Utf32 or Utf16/Utf8 byte length respectively. It should be noted that they do not operate on strings or arrays of characters directly. They simply multiply the supplied parameter by 4 in the case of QCHARLEN() or 2 (or 1) in the case of QOSCHARLEN().|
|QCHARLEN() & QOSCHARLEN() macros||These provide a simple conversion from a supplied byte length to the corresponding qchar or qoschar character length respectively. It should be noted that they do not operate on strings or arrays of characters directly. They simply divide the supplied parameter by 4 in the case of QCHARLEN() or 2 (or 1) in the case of QOSCHARLEN().|
(Defined in callback.h)
|This function converts a null-terminated string of 7-bit ASCII characters to qchars. The destination buffer must be pre-defined and large enough to contain the Utf32 data.|
|CHRcopyQcharStringToAscii||This function converts a null-terminated string
of qchars to 7-bit ASCII.
Assumes that the source text contains non-Unicode characters.
|CHRcopyAsciiDataToQchar||This function copies and converts the supplied string of ASCII characters to qchars. The source length must be supplied.|
|CHRcopyAsciiStringToQoschar||This function converts a null-terminated string of 7-bit ASCII characters to qoschars.|
|CHRcopyQoscharStringToAscii||This function converts a null-terminated string
of qoschars to 7-bit ASCII.
Assumes that the source text contains non-Unicode characters.
|CHRcopyAsciiDataToQoschar||This function copies and converts the supplied string of ASCII data to qoschars. The source length must be supplied.|
(Defined in omstring.h)
|There are a number of Omnis string functions to mirror the standard
C string functions. These operate on strings of qchars and are prefixed
to distinguish them from their ASCII counterparts. For example:
OMstrcpy, OMstrlen, OMstrncat & OMstrtok.
There are also functions to convert between character strings and integers: OMlongToString and OMstrtoul.
When loading resource strings (for example when responding to the ext_designinfo
dispatcher message), you should either use LoadStringW
for Unicode targets or LoadStringA and convert
to qchars using CHRcopyAsciiStringToQchar().
|LoadStringA(hInstLib, strid, buffer, 256); //Load resource
string into buffer
startPtr = strchr( buffer, '(' );
endPtr = strrchr( buffer, ')' );
length = (short) ( endptr - startptr + 1 ); //Extract text between the parentheses
if ((length > 0) && (startPtr) && (endPtr))
#ifdef isunicode //For the Unicode target- convert from ASCII to Utf32
*++endPtr = '\0'; //add null terminator
CHRcopyAsciiStringToQchar(startPtr, destPtr, qtrue);
#else //Otherwise just copy the ASCII text to the destination buffer
OMstrncpy((qchar *)destPtr, (qchar *)startPtr, length);
Reading Omnis FldVals
Old-style components typically exchange data with Omnis via GetFldVal
and SetFldVal callbacks.
There are a number of format specifiers to allow Unicode parameters to be passed:
|fmt_pstring||A pascal-style string of qchars- with the length value at element zero|
|fmt_cstring||A null-terminated string of qchars|
|fmt_hostring||A string of qoschars stored in handle-memory|
|fmt_costring||A null terminated string of qoschars|
|fmt_ostringlen||An integer value corresponding ot the character length the parameter|
|fmt_hutf8||Character data which is encoded as Utf8 and stored in handle memory|
|GetFldVal(ref_parm1, fmt_cstring, sizeof(buffer), &buffer, callback); //Get parameter as a string of qchars|
Writing Omnis FldVals
You can also write data back to Omnis FldVals using either the Utf8, Utf16 or Utf32 encoding using the format specifiers shown above:
|SetFldVal (ref_parm1 ,fmt_cstring, &buffer
,callback); //set buffer as a string of qchars
qoschar *myText = QTEXT("Default Value");
SetFldVal (ref_parm1 ,fmt_costring, myText ,callback); //set buffer as a string of qoschars
About Omnis Fonts
In order to display Unicode data in an Omnis field or in the method editor, an appropriate font must be chosen which supports the required subset of Unicode. Unicode Fonts typically support a range of Unicode characters, displaying characters outside this range as square blocks. Please refer to Technote TNXM0002 for an illustration.
Appendix - Building 64-bit Components October 2019
To build 64-bit external components, please contact Omnis Technical Support quoting fault reference ST/EC/1570 in order to obtain an updated callback.h header file. Changes to this file were made to address a structure packing mismatch between the component and the 64-bit Omnis core, for example when calling the core in order to obtain a list definition.
Sample Project and Omnis Library
The following sample project contains a simple character property which
can be set and retrieved using the Test_SetText and Test_GetText methods.
There is also a Test_Unicode method which illustrates setting of an Omnis
FldVal from a literal string of qoschars. The sample is supplied with
a Visual Studio 2008 project file.
An Omnis Studio 4.3.1 Unicode library is also provided which loads and calls these methods.
|Sample Library (utest.lbs)||Converting External Components to Unicode (pdf. See chapter 4)|
External Component SDK and Documentation: Component SDK