INtimeDotNet provides INtime NTX functions for .Net programs. Restrictions of the Common Language Runtime (CLR) versus the earlier C/C++ environment required certain modifications. INtimeDotNet requires Visual Studio 2005, or later.
With NTX (INtime's Windows API) functions, a Windows program can communicate with a real-time program running in the INtime real-time environment. NTX has evolved to support many versions of Windows.
In .Net, multiple programming languages target the same CLR and a whole framework of classes for .Net has emerged. Microsoft Visual Studio ships with CLR support for Visual Basic, C# and, in a slightly less structured way, C++ with managed extensions. Other software manufacturers offer additional programming languages.
The CLR provides:
The CLR does not provide an unsafe pointer type, and does not allow free casting from one type into another one.
Some NTX functions use untyped pointers that can even include NULL. Since the .NET framework does not accommodate this, NTX functions require a wrapper. In addition, the .NET framework uses exceptions extensively and, for various reasons, employs overloaded function definitions.
INtimeDotNet is a wrapper that integrates NTX into .Net. It is not a class framework. It matches NTX as closely as possible.
All INtimeDotNet functions are static members of the INtime class. This means you do not need to create an instance of the INtime class to access them. (In fact, this should cause a compiler error as the constructor is private.) Instead, you either qualify the function name by preceding it with INtime., or in the case of Visual Basic.Net, you may omit it if you have include an Imports INtime statement at the beginning of your program.
The next sections detail the main differences between NTX and INtimeDotNet.
INtimeDotNet deviates from NTX in these areas:
Further, INtimeDotNet does not include all NTX functions.
In the traditional Windows approach, when an exception occurs in NTX (for example, an invalid argument or a timeout while waiting for en event), a dedicated value returns and the programmer must then call ntxGetLastRtError to obtain the actual exception code.
In some cases a pointer value (-1 if an exception occurred) returns. The .NET framework cannot accept such pointer values. In addition, the .NET framework uses exceptions in many places. To conform to .NET style, INtimeDotNet uses exceptions in such cases. INtimeDotNet exceptions, derived from the Exception class, add a status member variable that contains the NTX exception code:
The INtimeException class
public class INtimeException : public System::Exception
{
INtimeException(UInt16 s) { status = s;};
UInt16 status;
};
The Exception class includes very detailed information regarding the exception's location and also includes the ToString member function that converts the information to a String.
The following code fragments illustrate first the NTX style, then the INtimeDotNet method (using Visual Basic and Visual C#):
Exception handling in NTX
NTXHANDLE hObject;
hObject = ntxCreateRtMailbox(hLocation, NTX_DATA_MAILBOX);
if (NTX_BAD_NTXHANDLE == hObject) {
status = ntxGetLastRtError();
// further exception handling
}
// use hObject
Exception handling in Visual Basic
Dim hObject As UInt32
Try
hObject = ntxCreateRtMailbox(hLocation, NTX_DATA_MAILBOX)
Catch exc As INtimeException
status = exc.status
' further exception handling
End Try
' use hObject
Exception handling in Visual C#
UInt32 hObject;
try {
hObject = INtime.ntxCreateRtMailbox(hLocation,
INtime.NTX_DATA_MAILBOX);
}
catch (INtimeException exc) {
status = exc.status;
// further exception handling
}
// use hObject
As a result of the use of exceptions, the INtimeDotNet functions never return these values:
NTX_ERROR NTX_BAD_NTXHANDLE BAD_POINTER BAD_TRANSACTION_ID NTX_BAD_SIZE
In many cases, NTX uses untyped or void pointers to refer to a buffer which contains only a series of bytes. Examples include the messages transmitted with ntxSendRtData or ntxReceiveRtData. This type of parameter is not legal in the CLR because pointers are not allowed
In standard C or C++, i.e., in NTX, a NULL can be passed as an argument to a function in lieu of a pointer to indicate that some default value should be used. Again, this is not legal in the CLR because pointers are not allowed. Instead, the following mechanism are used:
As an example, assume you have the following (packed) structure which you are using to send and receive messages:
Sample message layout
typedef struct {
WORD value1;
WORD value2;
DWORD value3;
unsigned char data[8];
} MESSAGE;
The following code fragments illustrate a message built and sent with NTX, Visual Basic, and Visual C# respectively.
Sending a message with NTX
MESSAGE msg;
memset (&msg, '\0', sizeof(msg));
WORD status;
msg.value1 = 1;
msg.value2 = 4;
msg.value3 = 100;
memcpy (msg.data, "Hello", strlen("Hello"));
status = ntxSendRtData(hMbox, &msg, sizeof(msg));
if (E_OK != status) {
// deal with exception 'status'
}
Sending a message with Visual Basic
The first options uses the different ntxSendRtData methods to send the data in the appropriate chunks. For example:
Imports INtime
Imports System.Text
Dim StrBuff() As Byte
StrBuff = Encoding.ASCII.GetBytes("Hello")
Try
ntxSendRtData2Bytes(hMbox, CShort(1))
ntxSendRtData2Bytes(hMbox, CShort(4))
ntxSendRtData4Bytes(hMbox, CInt(100))
ntxSendRtDataBytes(hMbox, StrBuff, StrBuff.Length)
Catch exc As INtimeException
'deal with exception in exc.status
End Try
The second alternative packs the data into an array of bytes and sends it all in one call. For example:
Dim DataBuf(128) As Byte
Array.Clear(DataBuf, 0, 128);
Dim ByteBuf() As Byte
Dim DCount As Integer = 0
ByteBuf = BitConverter.GetBytes(CShort(1))
ByteBuf.CopyTo(DataBuf, DCount)
DCount = DCount + ByteBuf.Length
ByteBuf = BitConverter.GetBytes(CShort(4))
ByteBuf.CopyTo(DataBuf, DCount)
DCount = DCount + ByteBuf.Length
ByteBuf = BitConverter.GetBytes(CInt(100))
ByteBuf.CopyTo(DataBuf, DCount)
DCount = DCount + ByteBuf.Length
ByteBuf = Encoding.ASCII.GetBytes("Hello")
ByteBuf.CopyTo(DataBuf, DCount)
DCount = DCount + ByteBuf.Length
Try
ntxSendRtDataBytes(hMbox, DataBuf, DCount)
Catch exc As INtimeException
'deal with exception in exc.status
End Try
Sending a message with Visual C#
Again, the first option sends pieces of the data in the appropriate chunks.
byte[] ByteBuf;
ByteBuf = Encoding.ASCII.GetBytes("Hello");
try {
INtime.ntxSendRtData2Bytes(hMbox, (Int16)1);
INtime.ntxSendRtData2Bytes(hMbox, (Int16)4);
INtime.ntxSendRtData4Bytes(hMbox, (Int32)100);
INtime.ntxSendRtDataBytes(hMbox, ByteBuf, ByteBuf.Length);
}
catch (INtimeException exc) {
// deal with exception exc.status
}
And the second option packs the data into a byte array and sends it all in one call.
const int RTBUFSIZE = 128;
byte[] DataBuf = new byte[RTBUFSIZE];
byte[] ByteBuf;
int DCount = 0;
Array.Clear(DataBuf, 0, RTBUFSIZE);
ByteBuf = BitConverter.GetBytes((Int16)(1));
ByteBuf.CopyTo(DataBuf, DCount);
DCount = DCount + ByteBuf.Length;
ByteBuf = BitConverter.GetBytes((Int16) (4));
ByteBuf.CopyTo(DataBuf, DCount);
DCount = DCount + ByteBuf.Length;
ByteBuf = BitConverter.GetBytes((Int32) (100));
ByteBuf.CopyTo(DataBuf, DCount);
DCount = DCount + ByteBuf.Length;
ByteBuf = Encoding.ASCII.GetBytes("Hello");
ByteBuf.CopyTo(DataBuf, DCount);
DCount = DCount + ByteBuf.Length;
try {
INtime.ntxSendRtDataBytes(hMbox, DataBuf, DCount);
}
catch (INtimeException exc) {
// deal with exception 'exc.status'
}
These NTX functions are not (directly) available in INtimeDotNet because of pointer limitations or because they have no use:
A .NET component contains both object code and interface definitions. To use the INtimeDotNet component in a Visual Studio project, you must add a reference to the component:
Importing INtimeDotNet names in Visual Basic
In Visual Basic, you can add a statement similar to this at the start of the program to avoid fully qualifying all names:
Imports INtime
Importing INtimeDotNet names in Visual C#
In Visual C#, you must qualify all constants, exception codes, and function names with "INtime". No using or namespace statements are required. For Example:
hMbox = INtime.ntxCreateRtMailbox(hLoc, INtime.NTX_DATA_MAILBOX);
The following constants are defined for exception codes, flags, and event codes.
In Visual Basic, you can use these constants directly; in Visual C# you must qualify the name with the INtime class name.
Description | Constants | |
---|---|---|
Exception codes (for details see INtime Status Codes) | E_OK E_TIME E_MEM E_BUSY E_LIMIT E_CONTEXT E_EXIST E_STATE E_SLOT E_NTX_INTERNAL_ERROR |
E_NTX_COMM_FAILURE E_NTX_DSM_INTERNAL_ERROR E_TYPE E_PARAM E_BAD_CALL E_PROTECTION E_BAD_ADDR E_STRING E_ALIGNMENT E_LOCATION |
Flags for creating objects | NTX_DATA_MAILBOX NTX_OBJECT_MAILBOX NTX_PRIORITY_QUEUING NTX_FIFO_QUEUING CREATE_UNBOUND (Object Mailbox Depth Flags) NTX_DEPTH_8 NTX_DEPTH_12 NTX_DEPTH_16 NTX_DEPTH_20 |
NTX_DEPTH_24 NTX_DEPTH_28 NTX_DEPTH_32 NTX_DEPTH_36 NTX_DEPTH_40 NTX_DEPTH_44 NTX_DEPTH_48 NTX_DEPTH_52 NTX_DEPTH_56 NTX_DEPTH_60 NTX_DEPTH_64 |
Possible return values from ntxGetRtType | NTX_TYPE_RT_PROCESS NTX_TYPE_RT_THREAD NTX_TYPE_MAILBOX NTX_TYPE_RT_SEMAPHORE NTX_TYPE_REGION NTX_TYPE_RT_SHARED_MEMORY |
NTX_TYPE_EXTENSION NTX_TYPE_PORT NTX_TYPE_POOL NTX_TYPE_HEAP NTX_TYPE_SERVICE |
Flags for ntxCreateRtProcess | NTX_PROC_DEBUG NTX_PROC_EXECUTABLE_DS |
NTX_PROC_SHOW_PROGRESS NTX_PROC_WAIT_FOR_INIT |
Flags for ntxNotifyEvent | NTX_SPONSOR_NOTIFICATIONS NTX_CLIENT_NOTIFICATIONS |
NTX_DEPENDENT_NOTIFICATIONS NTX_SYSTEM_EVENT_NOTIFICATIONS |
Types returned by ntxNofityEvent | DEPENDENT_REGISTERED DEPENDENT_UNREGISTERED DEPENDENT_TERMINATED SPONSOR_TERMINATED |
SPONSOR_UNREGISTERED RT_CLIENT_DOWN RT_CLIENT_UP |
Miscellaneous constants | NTX_NULL_NTXHANDLE NTX_LOCAL TERMINATE |
NTX_UNDEFINED_LOCATION NTX_INFINITE NTX_NO_WAIT |
This lists common operations on INtimeDotNet and the system calls that perform the operations:
To . . . | Use this system call . . . |
---|---|
Name an object in a process directory | ntxCatalogNtxHandle |
Create an RT mailbox | ntxCreateRtMailbox |
Load an RT executable and runs it in a new process | ntxCreateRtProcess |
Create an RT semaphore | ntxCreateRtSemaphore |
Delete an RT mailbox | ntxDeleteRtMailbox |
Delete an RT semaphore | ntxDeleteRtSemaphore |
Return a handle to the first known location | ntxGetFirstLocation |
Return a handle to the specified location | ntxGetLocationByName |
Return the name by which the specified location handle is known to NTX | ntxGetNameOfLocation |
Return the handle to the location following the one returned by the last call to ntxGetFirstLocation or ntxGetNextLocation in the current thread. | ntxGetNextLocation |
Obtain the root RT process handle | ntxGetRootRtProcess |
Return a string that contains the name of the status code passed | ntxGetRtErrorName |
Return a memory region's size | ntxGetRtSize |
Verify whether the RT kernel is successfully initialized | ntxGetRtStatus |
Return the type of an NTX handle | ntxGetType |
Obtain an NTXHANDLE that corresponds to an RTHANDLE | ntxImportRtHandle |
Return a short sentence (no punctuation) that describes "Status" | ntxLoadRtErrorString |
Search the given process's object directory for the given name and return the object handle, if found | ntxLookupNtxhandle |
Block until one of the desired notifications is received | ntxNotifyEvent |
Read from a Byte array or an INtime shared memory object | ntxReadRtXxx |
Wait for and then copy data out of an RT data mailbox | ntxReceiveRtDataXxx |
Receive handles from an object mailbox | ntxReceiveRtHandle |
Create a dependency relationship between the calling process and the specified sponsor | ntxRegisterDependency |
Register the calling process as a Sponsor with the given name | ntxRegisterSponsor |
Release units to an RT semaphore | ntxReleaseSemaphore |
Copy data to an RT data mailbox | ntxSendRtDataXxx |
Send an object handle to an object mailbox | ntxSendRtHandle |
Start an RT process previously loaded with ntxCreateRtProcess | ntxStartRtProcess |
Start a local INtime node | ntxStartLocalRtNode |
Stop a local INtime node | ntxStopLocalRtNode |
Remove an entry from a process' object directory | ntxUncatalogNtxHandle |
Remove the dependency relationship between the calling process and the specified sponsor | ntxUnregisterDependency |
Remove the current sponsor name from the active sponsor state. No notifications are made to dependents and the name remains in use until the sponsor is removed from all relationships | ntxUnregisterSponsor |
Wait for an RT process previously loaded with ntxCreateRtProcess to terminate | ntxWaitForRtProcess |
Request a specified number of units to be received from the RTsemaphore | ntxWaitForRtSemaphore |
Write to a Byte array or an INtime shared memory object | ntxWriteRtXxx |
Pass into ntxCreateRtProcess to overrule process creation defaults | NTXPROCATTRIBS |
Returns notifications about system state, sponsor processes, and dependent processes | NTXEVENTINFO |