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 is built as two distinct assemblies: a legacy build for .NET Framework 4.x, and a modern build shared by .NET 8 and .NET 10. The main body of this topic describes the Framework 4.x build, which most existing INtimeDotNet code targets. Where the modern .NET build differs — namespace, constructor visibility, and several parameter types — see Appendix A: .NET Framework 4.x vs. .NET 8 / .NET 10 Differences at the end of this topic.
INtimeDotNet defines a small set of aliases near the top of the header that map NTX C types onto CLR primitives. These names recur throughout the constants, structures, and functions described below.
| Alias | Underlying CLR Type | Meaning |
|---|---|---|
| NTXSTATUS | Int16 | NTX status / error code |
| NTXHANDLE | Int32 | Handle to an NTX object |
| RTHANDLE | Int16 | Native INtime (real-time) handle |
| NTXLOCATION | Int32 | RT node / location identifier |
| QWORD | unsigned long long | 64-bit unsigned |
| DWORD | unsigned int | 32-bit unsigned |
| WORD | unsigned short | 16-bit unsigned |
| BYTE | unsigned char | 8-bit unsigned |
| UINTPTR | QWORD on _WIN64, else DWORD | Pointer-sized unsigned |
| LPTSTR / LPCTSTR | TCHAR* / const TCHAR* | Native string buffer |
TCHAR is wchar_t under UNICODE, otherwise char.
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 ref class INtimeException : public System::Exception
Fields
| Member | Type | Description |
|---|---|---|
| status | NTXSTATUS | The NTX error code that caused the exception. |
| ntxLastErrorMessage | String^ | Optional last-error text from the driver. |
Constructors
| Signature | Purpose |
|---|---|
| INtimeException(NTXSTATUS s) | Status only. |
| INtimeException(NTXSTATUS s, Exception^ inner) | Status + inner exception. |
| INtimeException(NTXSTATUS s, String^ eMessage) | Status + message. |
| INtimeException(NTXSTATUS s, String^ eMessage, String^ lastError) | Status + message + driver last-error text. |
| INtimeException(NTXSTATUS s, String^ eMessage, Exception^ inner) | Status + message + inner exception. |
Methods
virtual String^ ToString() override;
// Returns: "Exception {status:X} - Message : {Message}"
The Exception class includes very detailed information regarding the exception's location.
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'
}
The examples above target the Framework 4.x build. In the modern .NET 8 / .NET 10 build, ntxSendRtData4Bytes takes a wider source value (UInt64 instead of Int32) — see Appendix A.
These NTX functions are not (directly) available in INtimeDotNet because of pointer limitations or because they have no use:
INtimeDotNet defines the following structures as CLR value types (value struct); identical in both the Framework 4.x and modern .NET builds.
NTXPROCATTRIBS — process pool/segment attributes (signed). Passed into ntxCreateRtProcess to overrule process creation defaults.
| Field | Type |
|---|---|
| dwPoolMin | Int32 |
| dwPoolMax | Int32 |
| dwVsegSize | Int32 |
| dwObjDirSize | Int32 |
NTXPROCATTRIBSEX — extended process attributes (unsigned, plus init wait).
| Field | Type |
|---|---|
| dwPoolMin, dwPoolMax, dwVsegSize, dwObjDirSize, dwWaitForInit | DWORD |
NTXEVENTINFO — event notification payload. Returns notifications about system state, sponsor processes, and dependent processes.
| Field | Type | Meaning |
|---|---|---|
| dwNotifyType | Int32 | One of the event codes listed under Constants. |
| hClient | NTXLOCATION | Originating location. |
| dwProcessId | NTXHANDLE | Process involved. |
NTXQUEUEINFO — queue state (see ntxGetRtQueueInfo, under Queue API).
| Field | Type |
|---|---|
| location | NTXLOCATION |
| MaxShortMsgSize | DWORD |
| QueueSize | DWORD |
| SpaceLeft | DWORD |
MSG_DESCRIPTOR — long-message descriptor (see ntxGetRtLongDataMessage, ntxGetMessageDescriptor, ntxCancelRtLongDataMessage, under Queue API).
| Field | Type |
|---|---|
| location | DWORD |
| msgid | DWORD |
| request | WORD |
| request_reply | WORD |
| dwUserParam | DWORD |
| length | DWORD |
| data | DWORD |
| reserved, reserved2 | DWORD |
NTXLOCATIONINFO (see ntxGetLocationInfo).
| Field | Type |
|---|---|
| LocationName | String^ |
| ClassName | String^ |
NTXNODEINFO (see ntxGetRtNodeInfo).
| Field | Type |
|---|---|
| hLocation | NTXLOCATION |
| nodeName | String^ |
| nodeId, nodeClass, nodeSubClass, netIdType | BYTE |
| netId | array<Byte>^ |
NTXNODEINFOEX — same as NTXNODEINFO except netId is BYTE^.
The matching ntxGetRtNodeInfoEx function is declared in the header but commented out, so it is not currently callable. Treat NTXNODEINFOEX as reference-only until that function is confirmed active.
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 guidance above applies to the Framework 4.x build. In the modern .NET 8 / .NET 10 build, these types live under an INtimeDotNet namespace instead — see Appendix A.
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_NOT_CONFIGURED E_SLOT E_VMEM E_CANCELLED E_NO_LOCAL_BUFFER E_NTX_INTERNAL_ERROR |
E_NTX_COMM_FAILURE E_NTX_KERNEL_FAILURE E_NTX_DSM_INTERNAL_ERROR E_TYPE E_PARAM E_BAD_CALL E_PROTECTION E_BAD_ADDR E_STRING E_PROTOCOL E_PORT_ID_USED E_NUC_BAD_BUF E_SEND_NOT_COMPLETE E_ALIGNMENT E_LOCATION |
| Deprecated exception codes, retained for source compatibility only (all collapse to the single value E_NOT_AN_NTX_ERROR) | E_INTERRUPT_SATURATION E_INTERRUPT_OVERFLOW E_DATA_CHAIN E_ZERO_DIVIDE E_OVERFLOW E_ARRAY_BOUNDS E_NDP_ERROR |
E_ILLEGAL_OPCODE E_EMULATOR_TRAP E_CHECK_EXCEPTION E_NOT_PRESENT E_CPU_XFER_DATA_LIMIT E_TRANSMISSION |
| Error / handle sentinels | NTX_ERROR NTX_BAD_SIZE NTX_BAD_NTXSTATUS NTX_BAD_NTXHANDLE |
NTX_UNKNOWN_ERROR_CODE_MESSAGE NTX_ALL_LOCAL_LOCATIONS |
| Memory-mapping options | NTX_MAP_WRITE | NTX_MAP_UNALIGNED |
| 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_REFOBJ NTX_TYPE_ALARM |
NTX_TYPE_EXTENSION NTX_TYPE_PORT NTX_TYPE_POOL NTX_TYPE_HEAP NTX_TYPE_SERVICE NTX_TYPE_FILE NTX_TYPE_QUEUE NTX_TYPE_RSL_OBJECT NTX_TYPE_RSL_REFERENCE |
| Flags for ntxCreateRtProcess | NTX_PROC_DEBUG NTX_PROC_EXECUTABLE_DS NTX_PROC_SHOW_PROGRESS NTX_PROC_WAIT_FOR_INIT NTX_PROC_WAIT_FOR_INIT_PARAM |
NTX_PROC_PIPE NTX_PROC_STRICTRSL NTX_PROC_SUSPEND NTX_PROC_XM NTX_PROC_NOTXM |
| 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 |
| I/O service wait flags | NTX_WAIT_FOR_IOPROXY | NTX_WAIT_FOR_IOSERVICE |
| Node / location classification | NTX_LOCAL_NODE NTX_REMOTE_NODE NTX_SHARED_NODE NTX_DEDICATED_NODE NTX_NODE_SUBCLASS_SHARED NTX_NODE_SUBCLASS_DEDICATED NTX_NODE_SUBCLASS_UNKNOWN |
NTX_NODE_SUBCLASS_PRIMARY NTX_NODE_SUBCLASS_SECONDARY NTX_NETID_TYPE_NONE NTX_NETID_TYPE_MAC NTX_NETID_TYPE_IP4 NTX_NETID_TYPE_IP6 NTX_REMOTE_GOBSNET |
| Sponsor-search modes | NTX_START_SEARCH NTX_CONTINUE_SEARCH |
NTX_THIS_LOCATION NTX_SPECIFIC_LOCATION |
| Miscellaneous constants | NTX_NULL_NTXHANDLE NTX_LOCAL TERMINATE |
NTX_UNDEFINED_LOCATION NTX_INFINITE NTX_NO_WAIT |
NTX_INFINITE and NTX_NO_WAIT are declared as a signed Int32 in the Framework 4.x build, but as an unsigned DWORD in the modern .NET 8 / .NET 10 build. Pass INtime.NTX_INFINITE / INtime.NTX_NO_WAIT rather than the literal -1 / 0 to stay build-agnostic. See Appendix A.
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 |
| Terminate an RT process | ntxTerminateRtProcess |
| Delete an RT process | ntxDeleteRtProcess |
| 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 |
| Return the location of an RT object | ntxGetLocationOfRtObject |
| Return detail information (name and class) for a location | ntxGetLocationInfo |
| Return node information for a location | ntxGetRtNodeInfo |
| 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 (or ntxRegisterDependencyEx, which also takes a location) |
| 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 (or ntxUnregisterDependencyEx, which also takes a location) |
| 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 |
| Locate a sponsor using one of the sponsor-search modes | ntxFindSponsor |
| 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 |
| Wait for an I/O service or I/O proxy | ntxWaitForIoService |
| Write to a Byte array or an INtime shared memory object | ntxWriteRtXxx |
| Return descriptive text for the last driver error | ntxGetLastRtError |
| Return the INtime version as a single number | ntxGetINtimeVersionNumber |
| Return the INtime product and update version strings | ntxGetINtimeVersion |
| Pass into ntxCreateRtProcess to overrule process creation defaults | NTXPROCATTRIBS |
| Returns notifications about system state, sponsor processes, and dependent processes | NTXEVENTINFO |
Reference pages for the newly added system calls in this table (ntxTerminateRtProcess, ntxDeleteRtProcess, ntxGetLocationOfRtObject, ntxGetLocationInfo, ntxGetRtNodeInfo, ntxRegisterDependencyEx, ntxUnregisterDependencyEx, ntxFindSponsor, ntxWaitForIoService, ntxGetLastRtErrorDescription, ntxGetINtimeVersionNumber, ntxGetINtimeVersion) have not been confirmed to exist yet in this help system, so they are listed here as plain text rather than links. Link them once their individual pages are published.
INtimeDotNet includes a set of queue functions and structures, added in 2014. These use bool return values (true on success) rather than the throw-on-error pattern used elsewhere in INtimeDotNet. Their parameters are DWORD in both the Framework 4.x and modern .NET builds, so this API is not affected by the Framework / .NET 8-10 signed/unsigned differences described in Appendix A.
| Function | Purpose |
|---|---|
| ntxCreateRtQueue(NTXLOCATION hLoc, DWORD queueSize, DWORD msgThreshold, DWORD flags) | Create an RT queue. |
| ntxDeleteRtQueue(NTXHANDLE hQueue) | Delete an RT queue. |
| ntxFlushRtQueue(NTXHANDLE hQueue) | Flush an RT queue. |
| ntxGetRtQueueInfo(NTXHANDLE hQueue, NTXQUEUEINFO% pQueueInfo) | Get queue state. |
| ntxLookupRtQueueHandle(NTXLOCATION hLoc, String^ QueueName, DWORD dwMilliseconds) | Look up a queue handle by name. |
| ntxCatalogRtQueueHandle(NTXHANDLE hQueue, String^ queueName) | Catalog a queue handle under a name. |
| ntxUncatalogRtQueueHandle(NTXHANDLE hQueue, String^ queueName) | Remove a queue's cataloged name. |
| ntxSendRtShortDataMessage(NTXHANDLE hQueue, array<Byte>^ msg, DWORD msgLength) | Send a short message. |
| ntxReceiveRtDataMessage(NTXHANDLE hQueue, array<Byte>^ msgBuffer, DWORD msgBufferSize, DWORD dwMilliseconds, DWORD% pMsgSize) | Receive a short message. |
| ntxSendRtLongDataMessage(NTXHANDLE hQueue, array<Byte>^ msg, DWORD msgLength, DWORD dwMilliseconds) | Send a long message. |
| ntxGetRtLongDataMessage(NTXHANDLE hQueue, MSG_DESCRIPTOR% msgDesc, array<Byte>^ msgBuffer, DWORD msgBufferLength, DWORD% msgSize) | Receive a long message. |
| ntxCancelRtLongDataMessage(NTXHANDLE hQueue, MSG_DESCRIPTOR% msgDesc) | Cancel a pending long message. |
| ntxGetMessageDescriptor(MSG_DESCRIPTOR% desc, array<Byte>^ msgBuffer, DWORD msgBufferSize) | Extract a message descriptor from a buffer. |
No Visual Basic or Visual C# worked example is available for the Queue API in the source material this topic was built from, so none is included here. If you would like one added, provide (or request drafting of) a sample usage and it can be inserted here in the same style as the Example Code section above.
INtimeDotNet compiles into two distinct assemblies, selected by the DOTNET452 preprocessor symbol:
| Build | DOTNET452 | Namespace | Notes |
|---|---|---|---|
| .NET Framework 4.x | Not defined | (global / none) | Legacy build. Types live in the global namespace. This is the build assumed throughout the main body of this topic. |
| Modern .NET (.NET 8 / .NET 10) | Defined | INtimeDotNet | The #else branch. The same branch is used for any non-Framework target, so .NET 8 and .NET 10 share identical surface area — there are no source differences between them. |
// Modern .NET 8/10 only:
namespace INtimeDotNet {
// INtimeException, INtime ...
}
In Framework builds there is no enclosing namespace, so fully-qualified names differ:
| Type | Framework 4.x | .NET 8 / .NET 10 |
|---|---|---|
| Exception | INtimeException | INtimeDotNet.INtimeException |
| Main class | INtime | INtimeDotNet.INtime |
| Build | Declaration | Effect |
|---|---|---|
| Framework 4.x | private: INtime(){} | Cannot be instantiated; use static members only. |
| .NET 8 / .NET 10 | public: INtime(){} | Public default constructor exists (still effectively a static-only class). |
In Framework builds, constants are declared with literal (compile-time) values. In modern .NET they are declared as static initonly (read-only static fields). The values themselves are identical — only the declaration kind, and in a few cases the field type (see A.4), differ.
This is the single most common difference encountered when porting. In Framework builds, many parameters and constants are declared as signed Int32. In modern .NET, the equivalent fields are declared as the unsigned DWORD / UInt32 / UInt64.
| Category | Framework 4.x | .NET 8/10 |
|---|---|---|
| Wait timeouts (NTX_INFINITE, NTX_NO_WAIT) | Int32 | DWORD |
| Mailbox/queue creation flags (NTX_DATA_MAILBOX, NTX_FIFO_QUEUING, etc.) | Int32 | DWORD (values unchanged) |
| Timeout params on lookup/receive/wait functions (e.g. ntxLookupNtxhandle, ntxReceiveRtDataXxx, ntxWaitForRtProcess, ntxRegisterDependency, ntxNotifyEvent) | Int32 | DWORD or UInt32 |
| Memory-offset parameters (pSrc/pDst in ntxReadRtXxx/ntxWriteRtXxx) | Int32 | UInt32 |
| hObj parameter to ntxGetType | Int32 | NTXHANDLE |
Pass INtime.NTX_INFINITE / INtime.NTX_NO_WAIT rather than literal -1 / 0, to stay build-agnostic.
| Build | lSrc parameter type |
|---|---|
| Framework 4.x | Int32 |
| .NET 8/10 | UInt64 |
This is a breaking change if porting code that currently passes an Int32 value directly.
The 2014 Queue API (documented above under Queue API) already used DWORD parameters in both builds, so it is unaffected by the signed/unsigned split described in A.4 and ports cleanly.